BadKB: Rename code to BadUSB for easier merges

Still called BadKB for display name and appid
This commit is contained in:
Willy-JL
2025-02-28 00:06:57 +00:00
parent 9e65b9472f
commit 02e00498a1
121 changed files with 1877 additions and 1852 deletions

View File

@@ -71,7 +71,7 @@ After installing the packs to Flipper, hit the <code>Arrow Up</code> button on t
<h2 align="center">Bad Keyboard:</h2>
<img src=".github/assets/badkb.png" align="left" width="250px"/>
BadUSB is a great app, but it lacks Bluetooth connectivity. Bad-KB allows you to toggle between USB and Bluetooth mode for your attacks.
BadUSB is a great app, but it lacks a lot of options. Bad-KB allows you to customize all USB and Bluetooth parameters for your attacks.
In Bluetooth mode it allows you to spoof the display name and MAC address of the device to whatever you want. Showing up as a portable speaker or a wireless keyboard is easily doable, allowing you to get the attention of your target without needing a cable at hand.

View File

@@ -25,7 +25,7 @@ Applications for factory testing the Flipper.
Applications for main Flipper menu.
- `archive` - Archive and file manager
- `bad_kb` - Bad KB application
- `bad_usb` - Bad KB application
- `gpio` - GPIO application: includes USART bridge and GPIO control
- `ibutton` - iButton application, onewire keys and more
- `infrared` - Infrared application, controls your IR devices

View File

@@ -47,7 +47,7 @@ FileBrowserApp* file_browser_app_alloc(char* arg) {
app->file_path = furi_string_alloc();
app->file_browser = file_browser_alloc(app->file_path);
file_browser_configure(app->file_browser, "*", NULL, true, false, &I_badkb_10px, true);
file_browser_configure(app->file_browser, "*", NULL, true, false, &I_badusb_10px, true);
view_dispatcher_add_view(
app->view_dispatcher, FileBrowserAppViewStart, widget_get_view(app->widget));

View File

Before

Width:  |  Height:  |  Size: 96 B

After

Width:  |  Height:  |  Size: 96 B

View File

@@ -14,7 +14,7 @@ static const char* tab_default_paths[] = {
[ArchiveTabSubGhz] = EXT_PATH("subghz"),
[ArchiveTabLFRFID] = EXT_PATH("lfrfid"),
[ArchiveTabInfrared] = EXT_PATH("infrared"),
[ArchiveTabBadKb] = EXT_PATH("badusb"),
[ArchiveTabBadUsb] = EXT_PATH("badusb"),
[ArchiveTabU2f] = "/app:u2f",
[ArchiveTabApplications] = EXT_PATH("apps"),
[ArchiveTabSearch] = "/app:search",
@@ -33,7 +33,7 @@ static const char* known_ext[] = {
[ArchiveFileTypeSubghzPlaylist] = ".txt",
[ArchiveFileTypeSubghzRemote] = ".txt",
[ArchiveFileTypeInfraredRemote] = ".txt",
[ArchiveFileTypeBadKb] = ".txt",
[ArchiveFileTypeBadUsb] = ".txt",
[ArchiveFileTypeWAV] = ".wav",
[ArchiveFileTypeMag] = ".mag",
[ArchiveFileTypeU2f] = "?",
@@ -55,7 +55,7 @@ static const ArchiveFileTypeEnum known_type[] = {
[ArchiveTabSubGhz] = ArchiveFileTypeSubGhz,
[ArchiveTabLFRFID] = ArchiveFileTypeLFRFID,
[ArchiveTabInfrared] = ArchiveFileTypeInfrared,
[ArchiveTabBadKb] = ArchiveFileTypeBadKb,
[ArchiveTabBadUsb] = ArchiveFileTypeBadUsb,
[ArchiveTabU2f] = ArchiveFileTypeU2f,
[ArchiveTabApplications] = ArchiveFileTypeAppOrJs,
[ArchiveTabSearch] = ArchiveFileTypeSearch,

View File

@@ -32,8 +32,8 @@ void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder
case ArchiveFileTypeInfraredRemote:
txt_path = IR_REMOTE_PATH;
break;
case ArchiveFileTypeBadKb:
txt_path = archive_get_default_path(ArchiveTabBadKb);
case ArchiveFileTypeBadUsb:
txt_path = archive_get_default_path(ArchiveTabBadUsb);
break;
}
if(txt_path != NULL) {

View File

@@ -18,7 +18,7 @@ typedef enum {
ArchiveFileTypeSubghzPlaylist,
ArchiveFileTypeSubghzRemote,
ArchiveFileTypeInfraredRemote,
ArchiveFileTypeBadKb,
ArchiveFileTypeBadUsb,
ArchiveFileTypeWAV,
ArchiveFileTypeMag,
ArchiveFileTypeU2f,

View File

@@ -29,7 +29,7 @@ const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) {
return EXT_PATH("apps/Sub-Ghz/subghz_remote.fap");
case ArchiveFileTypeInfraredRemote:
return EXT_PATH("apps/Infrared/ir_remote.fap");
case ArchiveFileTypeBadKb:
case ArchiveFileTypeBadUsb:
return "Bad KB";
case ArchiveFileTypeWAV:
return EXT_PATH("apps/Media/wav_player.fap");

View File

@@ -15,7 +15,7 @@ static const char* ArchiveTabNames[] = {
[ArchiveTabSubGhz] = "Sub-GHz",
[ArchiveTabLFRFID] = "RFID LF",
[ArchiveTabInfrared] = "Infrared",
[ArchiveTabBadKb] = "Bad KB",
[ArchiveTabBadUsb] = "Bad KB",
[ArchiveTabU2f] = "U2F",
[ArchiveTabApplications] = "Apps",
[ArchiveTabSearch] = "Search",
@@ -33,7 +33,7 @@ static const Icon* ArchiveItemIcons[] = {
[ArchiveFileTypeSubghzPlaylist] = &I_subplaylist_10px,
[ArchiveFileTypeSubghzRemote] = &I_subrem_10px,
[ArchiveFileTypeInfraredRemote] = &I_ir_scope_10px,
[ArchiveFileTypeBadKb] = &I_badkb_10px,
[ArchiveFileTypeBadUsb] = &I_badusb_10px,
[ArchiveFileTypeWAV] = &I_music_10px,
[ArchiveFileTypeMag] = &I_mag_card_10px,
[ArchiveFileTypeU2f] = &I_u2f_10px,

View File

@@ -28,7 +28,7 @@ typedef enum {
ArchiveTabNFC,
ArchiveTabInfrared,
ArchiveTabIButton,
ArchiveTabBadKb,
ArchiveTabBadUsb,
ArchiveTabU2f,
ArchiveTabApplications,
ArchiveTabSearch,

View File

@@ -1,811 +0,0 @@
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include <input/input.h>
#include <lib/toolbox/args.h>
#include <lib/toolbox/strint.h>
#include <storage/storage.h>
#include "ducky_script.h"
#include "ducky_script_i.h"
#include <dolphin/dolphin.h>
#define TAG "BadKb"
#define WORKER_TAG TAG "Worker"
#define BADKB_ASCII_TO_KEY(script, x) \
(((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE)
typedef enum {
WorkerEvtStartStop = (1 << 0),
WorkerEvtPauseResume = (1 << 1),
WorkerEvtEnd = (1 << 2),
WorkerEvtConnect = (1 << 3),
WorkerEvtDisconnect = (1 << 4),
} WorkerEvtFlags;
static const char ducky_cmd_id[] = {"ID"};
static const char ducky_cmd_bt_id[] = {"BT_ID"};
static const char ducky_cmd_ble_id[] = {"BLE_ID"};
static const uint8_t numpad_keys[10] = {
HID_KEYPAD_0,
HID_KEYPAD_1,
HID_KEYPAD_2,
HID_KEYPAD_3,
HID_KEYPAD_4,
HID_KEYPAD_5,
HID_KEYPAD_6,
HID_KEYPAD_7,
HID_KEYPAD_8,
HID_KEYPAD_9,
};
uint32_t ducky_get_command_len(const char* line) {
uint32_t len = strlen(line);
for(uint32_t i = 0; i < len; i++) {
if(line[i] == ' ') return i;
}
return 0;
}
bool ducky_is_line_end(const char chr) {
return (chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n');
}
uint16_t ducky_get_keycode(BadKbScript* bad_kb, const char* param, bool accept_chars) {
uint16_t keycode = ducky_get_keycode_by_name(param);
if(keycode != HID_KEYBOARD_NONE) {
return keycode;
}
if((accept_chars) && (strlen(param) > 0)) {
return BADKB_ASCII_TO_KEY(bad_kb, param[0]) & 0xFF;
}
return 0;
}
bool ducky_get_number(const char* param, uint32_t* val) {
uint32_t value = 0;
if(strint_to_uint32(param, NULL, &value, 10) == StrintParseNoError) {
*val = value;
return true;
}
return false;
}
void ducky_numlock_on(BadKbScript* bad_kb) {
if((bad_kb->hid->get_led_state(bad_kb->hid_inst) & HID_KB_LED_NUM) == 0) {
bad_kb->hid->kb_press(bad_kb->hid_inst, HID_KEYBOARD_LOCK_NUM_LOCK);
bad_kb->hid->kb_release(bad_kb->hid_inst, HID_KEYBOARD_LOCK_NUM_LOCK);
}
}
bool ducky_numpad_press(BadKbScript* bad_kb, const char num) {
if((num < '0') || (num > '9')) return false;
uint16_t key = numpad_keys[num - '0'];
bad_kb->hid->kb_press(bad_kb->hid_inst, key);
bad_kb->hid->kb_release(bad_kb->hid_inst, key);
return true;
}
bool ducky_altchar(BadKbScript* bad_kb, const char* charcode) {
uint8_t i = 0;
bool state = false;
bad_kb->hid->kb_press(bad_kb->hid_inst, KEY_MOD_LEFT_ALT);
while(!ducky_is_line_end(charcode[i])) {
state = ducky_numpad_press(bad_kb, charcode[i]);
if(state == false) break;
i++;
}
bad_kb->hid->kb_release(bad_kb->hid_inst, KEY_MOD_LEFT_ALT);
return state;
}
bool ducky_altstring(BadKbScript* bad_kb, const char* param) {
uint32_t i = 0;
bool state = false;
while(param[i] != '\0') {
if((param[i] < ' ') || (param[i] > '~')) {
i++;
continue; // Skip non-printable chars
}
char temp_str[4];
snprintf(temp_str, 4, "%u", param[i]);
state = ducky_altchar(bad_kb, temp_str);
if(state == false) break;
i++;
}
return state;
}
int32_t ducky_error(BadKbScript* bad_kb, const char* text, ...) {
va_list args;
va_start(args, text);
vsnprintf(bad_kb->st.error, sizeof(bad_kb->st.error), text, args);
va_end(args);
return SCRIPT_STATE_ERROR;
}
bool ducky_string(BadKbScript* bad_kb, const char* param) {
uint32_t i = 0;
while(param[i] != '\0') {
if(param[i] != '\n') {
uint16_t keycode = BADKB_ASCII_TO_KEY(bad_kb, param[i]);
if(keycode != HID_KEYBOARD_NONE) {
bad_kb->hid->kb_press(bad_kb->hid_inst, keycode);
bad_kb->hid->kb_release(bad_kb->hid_inst, keycode);
}
} else {
bad_kb->hid->kb_press(bad_kb->hid_inst, HID_KEYBOARD_RETURN);
bad_kb->hid->kb_release(bad_kb->hid_inst, HID_KEYBOARD_RETURN);
}
i++;
}
bad_kb->stringdelay = 0;
return true;
}
static bool ducky_string_next(BadKbScript* bad_kb) {
if(bad_kb->string_print_pos >= furi_string_size(bad_kb->string_print)) {
return true;
}
char print_char = furi_string_get_char(bad_kb->string_print, bad_kb->string_print_pos);
if(print_char != '\n') {
uint16_t keycode = BADKB_ASCII_TO_KEY(bad_kb, print_char);
if(keycode != HID_KEYBOARD_NONE) {
bad_kb->hid->kb_press(bad_kb->hid_inst, keycode);
bad_kb->hid->kb_release(bad_kb->hid_inst, keycode);
}
} else {
bad_kb->hid->kb_press(bad_kb->hid_inst, HID_KEYBOARD_RETURN);
bad_kb->hid->kb_release(bad_kb->hid_inst, HID_KEYBOARD_RETURN);
}
bad_kb->string_print_pos++;
return false;
}
static int32_t ducky_parse_line(BadKbScript* bad_kb, FuriString* line) {
uint32_t line_len = furi_string_size(line);
const char* line_tmp = furi_string_get_cstr(line);
if(line_len == 0) {
return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
}
FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp);
// Ducky Lang Functions
int32_t cmd_result = ducky_execute_cmd(bad_kb, line_tmp);
if(cmd_result != SCRIPT_STATE_CMD_UNKNOWN) {
return cmd_result;
}
// Mouse Keys
uint16_t key = ducky_get_mouse_keycode_by_name(line_tmp);
if(key != HID_MOUSE_INVALID) {
bad_kb->hid->mouse_press(bad_kb->hid_inst, key);
bad_kb->hid->mouse_release(bad_kb->hid_inst, key);
return 0;
}
// Special keys + modifiers
key = ducky_get_keycode(bad_kb, line_tmp, false);
if(key == HID_KEYBOARD_NONE) {
return ducky_error(bad_kb, "No keycode defined for %s", line_tmp);
}
if((key & 0xFF00) != 0) {
// It's a modifier key
uint32_t offset = ducky_get_command_len(line_tmp) + 1;
// ducky_get_command_len() returns 0 without space, so check for != 1
if(offset != 1 && line_len > offset) {
// It's also a key combination
line_tmp = &line_tmp[offset];
key |= ducky_get_keycode(bad_kb, line_tmp, true);
}
}
bad_kb->hid->kb_press(bad_kb->hid_inst, key);
bad_kb->hid->kb_release(bad_kb->hid_inst, key);
return 0;
}
static bool ducky_set_usb_id(BadKbScript* bad_kb, const char* line) {
FuriHalUsbHidConfig* usb_hid_cfg = &bad_kb->hid_cfg->usb;
if(sscanf(line, "%lX:%lX", &usb_hid_cfg->vid, &usb_hid_cfg->pid) == 2) {
usb_hid_cfg->manuf[0] = '\0';
usb_hid_cfg->product[0] = '\0';
uint8_t id_len = ducky_get_command_len(line);
if(!ducky_is_line_end(line[id_len + 1])) {
sscanf(
&line[id_len + 1],
"%31[^\r\n:]:%31[^\r\n]",
usb_hid_cfg->manuf,
usb_hid_cfg->product);
}
FURI_LOG_D(
WORKER_TAG,
"set id: %04lX:%04lX mfr:%s product:%s",
usb_hid_cfg->vid,
usb_hid_cfg->pid,
usb_hid_cfg->manuf,
usb_hid_cfg->product);
return true;
}
return false;
}
static bool ducky_set_ble_id(BadKbScript* bad_kb, const char* line) {
BleProfileHidParams* ble_hid_cfg = &bad_kb->hid_cfg->ble;
size_t line_len = strlen(line);
size_t mac_len = sizeof(ble_hid_cfg->mac) * 3; // 2 hex chars + separator per byte
if(line_len < mac_len + 1) return false; // MAC + at least 1 char for name
for(size_t i = 0; i < sizeof(ble_hid_cfg->mac); i++) {
const char* hex_byte = &line[i * 3];
// This sscanf() doesn't work well with %02hhX, need to use a u32
uint32_t temp_uint;
if(sscanf(hex_byte, "%02lX", &temp_uint) != 1) {
return false;
}
ble_hid_cfg->mac[sizeof(ble_hid_cfg->mac) - 1 - i] = temp_uint;
}
strlcpy(ble_hid_cfg->name, line + mac_len, sizeof(ble_hid_cfg->name));
FURI_LOG_D(WORKER_TAG, "set ble id: %s", line);
return true;
}
static void bad_kb_hid_state_callback(bool state, void* context) {
furi_assert(context);
BadKbScript* bad_kb = context;
if(state == true) {
furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtConnect);
} else {
furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtDisconnect);
}
}
static bool ducky_script_preload(BadKbScript* bad_kb, File* script_file) {
uint8_t ret = 0;
uint32_t line_len = 0;
furi_string_reset(bad_kb->line);
do {
ret = storage_file_read(script_file, bad_kb->file_buf, FILE_BUFFER_LEN);
for(uint16_t i = 0; i < ret; i++) {
if(bad_kb->file_buf[i] == '\n' && line_len > 0) {
bad_kb->st.line_nb++;
line_len = 0;
} else {
if(bad_kb->st.line_nb == 0) { // Save first line
furi_string_push_back(bad_kb->line, bad_kb->file_buf[i]);
}
line_len++;
}
}
if(storage_file_eof(script_file)) {
if(line_len > 0) {
bad_kb->st.line_nb++;
break;
}
}
} while(ret > 0);
if(bad_kb->load_id_cfg) {
const char* line_tmp = furi_string_get_cstr(bad_kb->line);
BadKbHidInterface interface = *bad_kb->interface;
// Look for ID/BLE_ID/BT_ID command on first line
if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) {
if(ducky_set_usb_id(bad_kb, &line_tmp[strlen(ducky_cmd_id) + 1])) {
interface = BadKbHidInterfaceUsb;
}
} else if(
strncmp(line_tmp, ducky_cmd_ble_id, strlen(ducky_cmd_ble_id)) == 0 ||
strncmp(line_tmp, ducky_cmd_bt_id, strlen(ducky_cmd_bt_id)) == 0) {
if(ducky_set_ble_id(bad_kb, &line_tmp[ducky_get_command_len(line_tmp) + 1])) {
interface = BadKbHidInterfaceBle;
}
}
// Auto-switch based on ID/BLE_ID/BT_ID command, user can override manually after
if(interface != *bad_kb->interface) {
*bad_kb->interface = interface;
bad_kb->hid = bad_kb_hid_get_interface(*bad_kb->interface);
}
}
bad_kb->hid_inst = bad_kb->hid->init(bad_kb->hid_cfg);
bad_kb->hid->set_state_callback(bad_kb->hid_inst, bad_kb_hid_state_callback, bad_kb);
storage_file_seek(script_file, 0, true);
furi_string_reset(bad_kb->line);
return true;
}
static int32_t ducky_script_execute_next(BadKbScript* bad_kb, File* script_file) {
int32_t delay_val = 0;
if(bad_kb->repeat_cnt > 0) {
bad_kb->repeat_cnt--;
delay_val = ducky_parse_line(bad_kb, bad_kb->line_prev);
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
return 0;
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
return delay_val;
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
return delay_val;
} else if(delay_val < 0) { // Script error
bad_kb->st.error_line = bad_kb->st.line_cur - 1;
FURI_LOG_E(WORKER_TAG, "Unknown command at line %zu", bad_kb->st.line_cur - 1U);
return SCRIPT_STATE_ERROR;
} else {
return delay_val + bad_kb->defdelay;
}
}
furi_string_set(bad_kb->line_prev, bad_kb->line);
furi_string_reset(bad_kb->line);
while(1) {
if(bad_kb->buf_len == 0) {
bad_kb->buf_len = storage_file_read(script_file, bad_kb->file_buf, FILE_BUFFER_LEN);
if(storage_file_eof(script_file)) {
if((bad_kb->buf_len < FILE_BUFFER_LEN) && (bad_kb->file_end == false)) {
bad_kb->file_buf[bad_kb->buf_len] = '\n';
bad_kb->buf_len++;
bad_kb->file_end = true;
}
}
bad_kb->buf_start = 0;
if(bad_kb->buf_len == 0) return SCRIPT_STATE_END;
}
for(uint8_t i = bad_kb->buf_start; i < (bad_kb->buf_start + bad_kb->buf_len); i++) {
if(bad_kb->file_buf[i] == '\n' && furi_string_size(bad_kb->line) > 0) {
bad_kb->st.line_cur++;
bad_kb->buf_len = bad_kb->buf_len + bad_kb->buf_start - (i + 1);
bad_kb->buf_start = i + 1;
furi_string_trim(bad_kb->line);
delay_val = ducky_parse_line(bad_kb, bad_kb->line);
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
return 0;
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
return delay_val;
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
return delay_val;
} else if(delay_val < 0) {
bad_kb->st.error_line = bad_kb->st.line_cur;
FURI_LOG_E(WORKER_TAG, "Unknown command at line %zu", bad_kb->st.line_cur);
return SCRIPT_STATE_ERROR;
} else {
return delay_val + bad_kb->defdelay;
}
} else {
furi_string_push_back(bad_kb->line, bad_kb->file_buf[i]);
}
}
bad_kb->buf_len = 0;
if(bad_kb->file_end) return SCRIPT_STATE_END;
}
return 0;
}
static uint32_t bad_kb_flags_get(uint32_t flags_mask, uint32_t timeout) {
uint32_t flags = furi_thread_flags_get();
furi_check((flags & FuriFlagError) == 0);
if(flags == 0) {
flags = furi_thread_flags_wait(flags_mask, FuriFlagWaitAny, timeout);
furi_check(((flags & FuriFlagError) == 0) || (flags == (unsigned)FuriFlagErrorTimeout));
} else {
uint32_t state = furi_thread_flags_clear(flags);
furi_check((state & FuriFlagError) == 0);
}
return flags;
}
static int32_t bad_kb_worker(void* context) {
BadKbScript* bad_kb = context;
BadKbWorkerState worker_state = BadKbStateInit;
BadKbWorkerState pause_state = BadKbStateRunning;
int32_t delay_val = 0;
FURI_LOG_I(WORKER_TAG, "Init");
File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
bad_kb->line = furi_string_alloc();
bad_kb->line_prev = furi_string_alloc();
bad_kb->string_print = furi_string_alloc();
bad_kb->st.elapsed = 0;
while(1) {
uint32_t start = furi_get_tick();
if(worker_state == BadKbStateInit) { // State: initialization
start = 0;
FURI_LOG_D(WORKER_TAG, "init start");
if(storage_file_open(
script_file,
furi_string_get_cstr(bad_kb->file_path),
FSAM_READ,
FSOM_OPEN_EXISTING)) {
if((ducky_script_preload(bad_kb, script_file)) && (bad_kb->st.line_nb > 0)) {
if(bad_kb->hid->is_connected(bad_kb->hid_inst)) {
worker_state = BadKbStateIdle; // Ready to run
} else {
worker_state = BadKbStateNotConnected; // USB not connected
}
} else {
worker_state = BadKbStateScriptError; // Script preload error
}
} else {
FURI_LOG_E(WORKER_TAG, "File open error");
worker_state = BadKbStateFileError; // File open error
}
bad_kb->st.state = worker_state;
FURI_LOG_D(WORKER_TAG, "init done");
} else if(worker_state == BadKbStateNotConnected) { // State: Not connected
start = 0;
FURI_LOG_D(WORKER_TAG, "not connected wait");
uint32_t flags = bad_kb_flags_get(
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop,
FuriWaitForever);
FURI_LOG_D(WORKER_TAG, "not connected flags: %lu", flags);
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtConnect) {
worker_state = BadKbStateIdle; // Ready to run
} else if(flags & WorkerEvtStartStop) {
worker_state = BadKbStateWillRun; // Will run when connected
}
bad_kb->st.state = worker_state;
} else if(worker_state == BadKbStateIdle) { // State: ready to start
start = 0;
FURI_LOG_D(WORKER_TAG, "idle wait");
uint32_t flags = bad_kb_flags_get(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtDisconnect, FuriWaitForever);
FURI_LOG_D(WORKER_TAG, "idle flags: %lu", flags);
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) { // Start executing script
dolphin_deed(DolphinDeedBadKbPlayScript);
delay_val = 0;
bad_kb->buf_len = 0;
bad_kb->st.line_cur = 0;
bad_kb->defdelay = 0;
bad_kb->stringdelay = 0;
bad_kb->defstringdelay = 0;
bad_kb->repeat_cnt = 0;
bad_kb->key_hold_nb = 0;
bad_kb->file_end = false;
storage_file_seek(script_file, 0, true);
worker_state = BadKbStateRunning;
bad_kb->st.elapsed = 0;
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadKbStateNotConnected; // Disconnected
}
bad_kb->st.state = worker_state;
} else if(worker_state == BadKbStateWillRun) { // State: start on connection
start = 0;
FURI_LOG_D(WORKER_TAG, "will run wait");
uint32_t flags = bad_kb_flags_get(
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtStartStop, FuriWaitForever);
FURI_LOG_D(WORKER_TAG, "will run flags: %lu", flags);
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtConnect) { // Start executing script
dolphin_deed(DolphinDeedBadKbPlayScript);
delay_val = 0;
bad_kb->buf_len = 0;
bad_kb->st.line_cur = 0;
bad_kb->defdelay = 0;
bad_kb->stringdelay = 0;
bad_kb->defstringdelay = 0;
bad_kb->repeat_cnt = 0;
bad_kb->file_end = false;
storage_file_seek(script_file, 0, true);
// extra time for PC to recognize Flipper as keyboard
flags = furi_thread_flags_wait(
WorkerEvtEnd | WorkerEvtDisconnect | WorkerEvtStartStop,
FuriFlagWaitAny | FuriFlagNoClear,
1500);
if(flags == (unsigned)FuriFlagErrorTimeout) {
// If nothing happened - start script execution
worker_state = BadKbStateRunning;
bad_kb->st.elapsed = 0;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadKbStateIdle;
furi_thread_flags_clear(WorkerEvtStartStop);
}
} else if(flags & WorkerEvtStartStop) { // Cancel scheduled execution
worker_state = BadKbStateNotConnected;
}
bad_kb->st.state = worker_state;
} else if(worker_state == BadKbStateRunning) { // State: running
FURI_LOG_D(WORKER_TAG, "running");
uint16_t delay_cur = (delay_val > 100) ? (100) : (delay_val);
uint32_t flags = furi_thread_flags_wait(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect,
FuriFlagWaitAny,
delay_cur);
FURI_LOG_D(WORKER_TAG, "running flags: %lu", flags);
delay_val -= delay_cur;
if(!(flags & FuriFlagError)) {
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadKbStateIdle; // Stop executing script
bad_kb->hid->release_all(bad_kb->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadKbStateNotConnected; // Disconnected
bad_kb->hid->release_all(bad_kb->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
pause_state = BadKbStateRunning;
worker_state = BadKbStatePaused; // Pause
}
bad_kb->st.state = worker_state;
bad_kb->st.elapsed += (furi_get_tick() - start);
continue;
} else if(
(flags == (unsigned)FuriFlagErrorTimeout) ||
(flags == (unsigned)FuriFlagErrorResource)) {
if(delay_val > 0) {
bad_kb->st.delay_remain--;
bad_kb->st.elapsed += (furi_get_tick() - start);
continue;
}
bad_kb->st.state = BadKbStateRunning;
delay_val = ducky_script_execute_next(bad_kb, script_file);
if(delay_val == SCRIPT_STATE_ERROR) { // Script error
delay_val = 0;
worker_state = BadKbStateScriptError;
bad_kb->st.state = worker_state;
bad_kb->hid->release_all(bad_kb->hid_inst);
} else if(delay_val == SCRIPT_STATE_END) { // End of script
delay_val = 0;
worker_state = BadKbStateIdle;
bad_kb->st.state = BadKbStateDone;
bad_kb->hid->release_all(bad_kb->hid_inst);
bad_kb->st.elapsed += (furi_get_tick() - start);
continue;
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays
delay_val = bad_kb->defdelay;
bad_kb->string_print_pos = 0;
worker_state = BadKbStateStringDelay;
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // set state to wait for user input
worker_state = BadKbStateWaitForBtn;
bad_kb->st.state = BadKbStateWaitForBtn; // Show long delays
} else if(delay_val > 100) {
bad_kb->st.state = BadKbStateDelay; // Show long delays
bad_kb->st.delay_remain = delay_val / 100;
}
} else {
furi_check((flags & FuriFlagError) == 0);
}
} else if(worker_state == BadKbStateWaitForBtn) { // State: Wait for button Press
start = 0;
FURI_LOG_D(WORKER_TAG, "button wait");
uint32_t flags = bad_kb_flags_get(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect,
FuriWaitForever);
FURI_LOG_D(WORKER_TAG, "button flags: %lu", flags);
if(!(flags & FuriFlagError)) {
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) {
delay_val = 0;
worker_state = BadKbStateRunning;
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadKbStateNotConnected; // Disconnected
bad_kb->hid->release_all(bad_kb->hid_inst);
}
bad_kb->st.state = worker_state;
continue;
}
} else if(worker_state == BadKbStatePaused) { // State: Paused
start = 0;
FURI_LOG_D(WORKER_TAG, "paused wait");
uint32_t flags = bad_kb_flags_get(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect,
FuriWaitForever);
FURI_LOG_D(WORKER_TAG, "paused flags: %lu", flags);
if(!(flags & FuriFlagError)) {
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadKbStateIdle; // Stop executing script
bad_kb->st.state = worker_state;
bad_kb->hid->release_all(bad_kb->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadKbStateNotConnected; // Disconnected
bad_kb->st.state = worker_state;
bad_kb->hid->release_all(bad_kb->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
if(pause_state == BadKbStateRunning) {
if(delay_val > 0) {
bad_kb->st.state = BadKbStateDelay;
bad_kb->st.delay_remain = delay_val / 100;
} else {
bad_kb->st.state = BadKbStateRunning;
delay_val = 0;
}
worker_state = BadKbStateRunning; // Resume
} else if(pause_state == BadKbStateStringDelay) {
bad_kb->st.state = BadKbStateRunning;
worker_state = BadKbStateStringDelay; // Resume
}
}
continue;
}
} else if(worker_state == BadKbStateStringDelay) { // State: print string with delays
FURI_LOG_D(WORKER_TAG, "delay wait");
uint32_t delay = (bad_kb->stringdelay == 0) ? bad_kb->defstringdelay :
bad_kb->stringdelay;
uint32_t flags = bad_kb_flags_get(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect,
delay);
FURI_LOG_D(WORKER_TAG, "delay flags: %lu", flags);
if(!(flags & FuriFlagError)) {
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadKbStateIdle; // Stop executing script
bad_kb->hid->release_all(bad_kb->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadKbStateNotConnected; // Disconnected
bad_kb->hid->release_all(bad_kb->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
pause_state = BadKbStateStringDelay;
worker_state = BadKbStatePaused; // Pause
}
bad_kb->st.state = worker_state;
bad_kb->st.elapsed += (furi_get_tick() - start);
continue;
} else if(
(flags == (unsigned)FuriFlagErrorTimeout) ||
(flags == (unsigned)FuriFlagErrorResource)) {
bool string_end = ducky_string_next(bad_kb);
if(string_end) {
bad_kb->stringdelay = 0;
worker_state = BadKbStateRunning;
}
} else {
furi_check((flags & FuriFlagError) == 0);
}
} else if(
(worker_state == BadKbStateFileError) ||
(worker_state == BadKbStateScriptError)) { // State: error
start = 0;
FURI_LOG_D(WORKER_TAG, "error wait");
uint32_t flags =
bad_kb_flags_get(WorkerEvtEnd, FuriWaitForever); // Waiting for exit command
FURI_LOG_D(WORKER_TAG, "error flags: %lu", flags);
if(flags & WorkerEvtEnd) {
break;
}
}
if(start) {
bad_kb->st.elapsed += (furi_get_tick() - start);
}
}
bad_kb->hid->set_state_callback(bad_kb->hid_inst, NULL, NULL);
bad_kb->hid->deinit(bad_kb->hid_inst);
storage_file_close(script_file);
storage_file_free(script_file);
furi_string_free(bad_kb->line);
furi_string_free(bad_kb->line_prev);
furi_string_free(bad_kb->string_print);
FURI_LOG_I(WORKER_TAG, "End");
return 0;
}
static void bad_kb_script_set_default_keyboard_layout(BadKbScript* bad_kb) {
furi_assert(bad_kb);
memset(bad_kb->layout, HID_KEYBOARD_NONE, sizeof(bad_kb->layout));
memcpy(bad_kb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_kb->layout)));
}
BadKbScript* bad_kb_script_open(
FuriString* file_path,
BadKbHidInterface* interface,
BadKbHidConfig* hid_cfg,
bool load_id_cfg) {
furi_assert(file_path);
BadKbScript* bad_kb = malloc(sizeof(BadKbScript));
bad_kb->file_path = furi_string_alloc();
furi_string_set(bad_kb->file_path, file_path);
bad_kb_script_set_default_keyboard_layout(bad_kb);
bad_kb->st.state = BadKbStateInit;
bad_kb->st.error[0] = '\0';
bad_kb->interface = interface;
bad_kb->hid_cfg = hid_cfg;
bad_kb->load_id_cfg = load_id_cfg;
bad_kb->hid = bad_kb_hid_get_interface(*bad_kb->interface);
bad_kb->thread = furi_thread_alloc_ex("BadKbWorker", 2048, bad_kb_worker, bad_kb);
furi_thread_start(bad_kb->thread);
return bad_kb;
} //-V773
void bad_kb_script_close(BadKbScript* bad_kb) {
furi_assert(bad_kb);
furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtEnd);
furi_thread_join(bad_kb->thread);
furi_thread_free(bad_kb->thread);
furi_string_free(bad_kb->file_path);
free(bad_kb);
}
void bad_kb_script_set_keyboard_layout(BadKbScript* bad_kb, FuriString* layout_path) {
furi_assert(bad_kb);
if((bad_kb->st.state == BadKbStateRunning) || (bad_kb->st.state == BadKbStateDelay)) {
// 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)) { //-V1051
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_kb->layout, layout, sizeof(layout));
}
}
storage_file_close(layout_file);
} else {
bad_kb_script_set_default_keyboard_layout(bad_kb);
}
storage_file_free(layout_file);
}
void bad_kb_script_start_stop(BadKbScript* bad_kb) {
furi_assert(bad_kb);
furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtStartStop);
}
void bad_kb_script_pause_resume(BadKbScript* bad_kb) {
furi_assert(bad_kb);
furi_thread_flags_set(furi_thread_get_id(bad_kb->thread), WorkerEvtPauseResume);
}
BadKbState* bad_kb_script_get_state(BadKbScript* bad_kb) {
furi_assert(bad_kb);
return &(bad_kb->st);
}

View File

@@ -1,60 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <furi.h>
#include <furi_hal.h>
#include "bad_kb_hid.h"
typedef enum {
BadKbStateInit,
BadKbStateNotConnected,
BadKbStateIdle,
BadKbStateWillRun,
BadKbStateRunning,
BadKbStateDelay,
BadKbStateStringDelay,
BadKbStateWaitForBtn,
BadKbStatePaused,
BadKbStateDone,
BadKbStateScriptError,
BadKbStateFileError,
} BadKbWorkerState;
typedef struct {
BadKbWorkerState state;
size_t line_cur;
size_t line_nb;
uint32_t delay_remain;
size_t error_line;
char error[64];
uint32_t elapsed;
} BadKbState;
typedef struct BadKbScript BadKbScript;
BadKbScript* bad_kb_script_open(
FuriString* file_path,
BadKbHidInterface* interface,
BadKbHidConfig* hid_cfg,
bool load_id_cfg);
void bad_kb_script_close(BadKbScript* bad_kb);
void bad_kb_script_set_keyboard_layout(BadKbScript* bad_kb, FuriString* layout_path);
void bad_kb_script_start(BadKbScript* bad_kb);
void bad_kb_script_stop(BadKbScript* bad_kb);
void bad_kb_script_start_stop(BadKbScript* bad_kb);
void bad_kb_script_pause_resume(BadKbScript* bad_kb);
BadKbState* bad_kb_script_get_state(BadKbScript* bad_kb);
#ifdef __cplusplus
}
#endif

View File

@@ -1,30 +0,0 @@
#include "bad_kb_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const bad_kb_scene_on_enter_handlers[])(void*) = {
#include "bad_kb_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const bad_kb_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "bad_kb_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const bad_kb_scene_on_exit_handlers[])(void* context) = {
#include "bad_kb_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers bad_kb_scene_handlers = {
.on_enter_handlers = bad_kb_scene_on_enter_handlers,
.on_event_handlers = bad_kb_scene_on_event_handlers,
.on_exit_handlers = bad_kb_scene_on_exit_handlers,
.scene_num = BadKbSceneNum,
};

View File

@@ -1,11 +0,0 @@
ADD_SCENE(bad_kb, file_select, FileSelect)
ADD_SCENE(bad_kb, work, Work)
ADD_SCENE(bad_kb, error, Error)
ADD_SCENE(bad_kb, config, Config)
ADD_SCENE(bad_kb, config_layout, ConfigLayout)
ADD_SCENE(bad_kb, config_ble_name, ConfigBleName)
ADD_SCENE(bad_kb, config_ble_mac, ConfigBleMac)
ADD_SCENE(bad_kb, config_usb_name, ConfigUsbName)
ADD_SCENE(bad_kb, config_usb_vidpid, ConfigUsbVidPid)
ADD_SCENE(bad_kb, confirm_unpair, ConfirmUnpair)
ADD_SCENE(bad_kb, unpair_done, UnpairDone)

View File

@@ -1,71 +0,0 @@
#include "../bad_kb_app_i.h"
enum ByteInputResult {
ByteInputResultOk,
};
static void reverse_mac_addr(uint8_t mac_addr[GAP_MAC_ADDR_SIZE]) {
uint8_t tmp;
for(size_t i = 0; i < GAP_MAC_ADDR_SIZE / 2; i++) {
tmp = mac_addr[i];
mac_addr[i] = mac_addr[GAP_MAC_ADDR_SIZE - 1 - i];
mac_addr[GAP_MAC_ADDR_SIZE - 1 - i] = tmp;
}
}
void bad_kb_scene_config_ble_mac_byte_input_callback(void* context) {
BadKbApp* bad_kb = context;
view_dispatcher_send_custom_event(bad_kb->view_dispatcher, ByteInputResultOk);
}
void bad_kb_scene_config_ble_mac_on_enter(void* context) {
BadKbApp* bad_kb = context;
ByteInput* byte_input = bad_kb->byte_input;
memcpy(bad_kb->ble_mac_buf, bad_kb->script_hid_cfg.ble.mac, sizeof(bad_kb->ble_mac_buf));
reverse_mac_addr(bad_kb->ble_mac_buf);
byte_input_set_header_text(byte_input, "Set BLE MAC address");
byte_input_set_result_callback(
byte_input,
bad_kb_scene_config_ble_mac_byte_input_callback,
NULL,
bad_kb,
bad_kb->ble_mac_buf,
sizeof(bad_kb->ble_mac_buf));
view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewByteInput);
}
bool bad_kb_scene_config_ble_mac_on_event(void* context, SceneManagerEvent event) {
BadKbApp* bad_kb = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == ByteInputResultOk) {
reverse_mac_addr(bad_kb->ble_mac_buf);
// Apply to current script config
memcpy(
bad_kb->script_hid_cfg.ble.mac,
bad_kb->ble_mac_buf,
sizeof(bad_kb->script_hid_cfg.ble.mac));
// Set in user config to save in settings file
memcpy(
bad_kb->user_hid_cfg.ble.mac,
bad_kb->ble_mac_buf,
sizeof(bad_kb->user_hid_cfg.ble.mac));
}
scene_manager_previous_scene(bad_kb->scene_manager);
}
return consumed;
}
void bad_kb_scene_config_ble_mac_on_exit(void* context) {
BadKbApp* bad_kb = context;
ByteInput* byte_input = bad_kb->byte_input;
byte_input_set_result_callback(byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(byte_input, "");
}

View File

@@ -1,59 +0,0 @@
#include "../bad_kb_app_i.h"
enum TextInputResult {
TextInputResultOk,
};
static void bad_kb_scene_config_ble_name_text_input_callback(void* context) {
BadKbApp* bad_kb = context;
view_dispatcher_send_custom_event(bad_kb->view_dispatcher, TextInputResultOk);
}
void bad_kb_scene_config_ble_name_on_enter(void* context) {
BadKbApp* bad_kb = context;
TextInput* text_input = bad_kb->text_input;
strlcpy(bad_kb->ble_name_buf, bad_kb->script_hid_cfg.ble.name, sizeof(bad_kb->ble_name_buf));
text_input_set_header_text(text_input, "Set BLE device name");
text_input_set_result_callback(
text_input,
bad_kb_scene_config_ble_name_text_input_callback,
bad_kb,
bad_kb->ble_name_buf,
sizeof(bad_kb->ble_name_buf),
true);
view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewTextInput);
}
bool bad_kb_scene_config_ble_name_on_event(void* context, SceneManagerEvent event) {
BadKbApp* bad_kb = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == TextInputResultOk) {
// Apply to current script config
strlcpy(
bad_kb->script_hid_cfg.ble.name,
bad_kb->ble_name_buf,
sizeof(bad_kb->script_hid_cfg.ble.name));
// Set in user config to save in settings file
strlcpy(
bad_kb->user_hid_cfg.ble.name,
bad_kb->ble_name_buf,
sizeof(bad_kb->user_hid_cfg.ble.name));
}
scene_manager_previous_scene(bad_kb->scene_manager);
}
return consumed;
}
void bad_kb_scene_config_ble_name_on_exit(void* context) {
BadKbApp* bad_kb = context;
TextInput* text_input = bad_kb->text_input;
text_input_reset(text_input);
}

View File

@@ -1,45 +0,0 @@
#include "../bad_kb_app_i.h"
#include <storage/storage.h>
static bool bad_kb_layout_select(BadKbApp* bad_kb) {
furi_assert(bad_kb);
FuriString* predefined_path;
predefined_path = furi_string_alloc();
if(!furi_string_empty(bad_kb->keyboard_layout)) {
furi_string_set(predefined_path, bad_kb->keyboard_layout);
} else {
furi_string_set(predefined_path, BAD_KB_APP_PATH_LAYOUT_FOLDER);
}
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(
&browser_options, BAD_KB_APP_LAYOUT_EXTENSION, &I_keyboard_10px);
browser_options.base_path = BAD_KB_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_kb->dialogs, bad_kb->keyboard_layout, predefined_path, &browser_options);
furi_string_free(predefined_path);
return res;
}
void bad_kb_scene_config_layout_on_enter(void* context) {
BadKbApp* bad_kb = context;
bad_kb_layout_select(bad_kb);
scene_manager_previous_scene(bad_kb->scene_manager);
}
bool bad_kb_scene_config_layout_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void bad_kb_scene_config_layout_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -1,81 +0,0 @@
#include "../bad_kb_app_i.h"
enum TextInputResult {
TextInputResultOk,
};
static void bad_kb_scene_config_usb_name_text_input_callback(void* context) {
BadKbApp* bad_kb = context;
view_dispatcher_send_custom_event(bad_kb->view_dispatcher, TextInputResultOk);
}
void bad_kb_scene_config_usb_name_on_enter(void* context) {
BadKbApp* bad_kb = context;
TextInput* text_input = bad_kb->text_input;
if(scene_manager_get_scene_state(bad_kb->scene_manager, BadKbSceneConfigUsbName)) {
strlcpy(
bad_kb->usb_name_buf, bad_kb->script_hid_cfg.usb.manuf, sizeof(bad_kb->usb_name_buf));
text_input_set_header_text(text_input, "Set USB manufacturer name");
} else {
strlcpy(
bad_kb->usb_name_buf,
bad_kb->script_hid_cfg.usb.product,
sizeof(bad_kb->usb_name_buf));
text_input_set_header_text(text_input, "Set USB product name");
}
text_input_set_result_callback(
text_input,
bad_kb_scene_config_usb_name_text_input_callback,
bad_kb,
bad_kb->usb_name_buf,
sizeof(bad_kb->usb_name_buf),
true);
view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewTextInput);
}
bool bad_kb_scene_config_usb_name_on_event(void* context, SceneManagerEvent event) {
BadKbApp* bad_kb = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == TextInputResultOk) {
if(scene_manager_get_scene_state(bad_kb->scene_manager, BadKbSceneConfigUsbName)) {
// Apply to current script config
strlcpy(
bad_kb->script_hid_cfg.usb.manuf,
bad_kb->usb_name_buf,
sizeof(bad_kb->script_hid_cfg.usb.manuf));
// Set in user config to save in settings file
strlcpy(
bad_kb->user_hid_cfg.usb.manuf,
bad_kb->usb_name_buf,
sizeof(bad_kb->user_hid_cfg.usb.manuf));
} else {
// Apply to current script config
strlcpy(
bad_kb->script_hid_cfg.usb.product,
bad_kb->usb_name_buf,
sizeof(bad_kb->script_hid_cfg.usb.product));
// Set in user config to save in settings file
strlcpy(
bad_kb->user_hid_cfg.usb.product,
bad_kb->usb_name_buf,
sizeof(bad_kb->user_hid_cfg.usb.product));
}
}
scene_manager_previous_scene(bad_kb->scene_manager);
}
return consumed;
}
void bad_kb_scene_config_usb_name_on_exit(void* context) {
BadKbApp* bad_kb = context;
TextInput* text_input = bad_kb->text_input;
text_input_reset(text_input);
}

View File

@@ -1,57 +0,0 @@
#include "../bad_kb_app_i.h"
enum ByteInputResult {
ByteInputResultOk,
};
void bad_kb_scene_config_usb_vidpid_byte_input_callback(void* context) {
BadKbApp* bad_kb = context;
view_dispatcher_send_custom_event(bad_kb->view_dispatcher, ByteInputResultOk);
}
void bad_kb_scene_config_usb_vidpid_on_enter(void* context) {
BadKbApp* bad_kb = context;
ByteInput* byte_input = bad_kb->byte_input;
bad_kb->usb_vidpid_buf[0] = __REVSH(bad_kb->script_hid_cfg.usb.vid);
bad_kb->usb_vidpid_buf[1] = __REVSH(bad_kb->script_hid_cfg.usb.pid);
byte_input_set_header_text(byte_input, "Set USB VID:PID");
byte_input_set_result_callback(
byte_input,
bad_kb_scene_config_usb_vidpid_byte_input_callback,
NULL,
bad_kb,
(void*)bad_kb->usb_vidpid_buf,
sizeof(bad_kb->usb_vidpid_buf));
view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewByteInput);
}
bool bad_kb_scene_config_usb_vidpid_on_event(void* context, SceneManagerEvent event) {
BadKbApp* bad_kb = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == ByteInputResultOk) {
// Apply to current script config
bad_kb->script_hid_cfg.usb.vid = __REVSH(bad_kb->usb_vidpid_buf[0]);
bad_kb->script_hid_cfg.usb.pid = __REVSH(bad_kb->usb_vidpid_buf[1]);
// Set in user config to save in settings file
bad_kb->user_hid_cfg.usb.vid = bad_kb->script_hid_cfg.usb.vid;
bad_kb->user_hid_cfg.usb.pid = bad_kb->script_hid_cfg.usb.pid;
}
scene_manager_previous_scene(bad_kb->scene_manager);
}
return consumed;
}
void bad_kb_scene_config_usb_vidpid_on_exit(void* context) {
BadKbApp* bad_kb = context;
ByteInput* byte_input = bad_kb->byte_input;
byte_input_set_result_callback(byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(byte_input, "");
}

View File

@@ -1,49 +0,0 @@
#include "../bad_kb_app_i.h"
void bad_kb_scene_confirm_unpair_widget_callback(
GuiButtonType type,
InputType input_type,
void* context) {
UNUSED(input_type);
SceneManagerEvent event = {.type = SceneManagerEventTypeCustom, .event = type};
bad_kb_scene_confirm_unpair_on_event(context, event);
}
void bad_kb_scene_confirm_unpair_on_enter(void* context) {
BadKbApp* bad_kb = context;
Widget* widget = bad_kb->widget;
widget_add_button_element(
widget, GuiButtonTypeLeft, "Cancel", bad_kb_scene_confirm_unpair_widget_callback, context);
widget_add_button_element(
widget, GuiButtonTypeRight, "Unpair", bad_kb_scene_confirm_unpair_widget_callback, context);
widget_add_text_box_element(
widget, 0, 0, 128, 64, AlignCenter, AlignTop, "\e#Unpair the Device?\e#\n", false);
view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewWidget);
}
bool bad_kb_scene_confirm_unpair_on_event(void* context, SceneManagerEvent event) {
BadKbApp* bad_kb = context;
SceneManager* scene_manager = bad_kb->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(scene_manager, BadKbSceneUnpairDone);
} else if(event.event == GuiButtonTypeLeft) {
scene_manager_previous_scene(scene_manager);
}
}
return consumed;
}
void bad_kb_scene_confirm_unpair_on_exit(void* context) {
BadKbApp* bad_kb = context;
Widget* widget = bad_kb->widget;
widget_reset(widget);
}

View File

@@ -1,39 +0,0 @@
#include "../bad_kb_app_i.h"
static void bad_kb_scene_unpair_done_popup_callback(void* context) {
BadKbApp* bad_kb = context;
scene_manager_search_and_switch_to_previous_scene(bad_kb->scene_manager, BadKbSceneConfig);
}
void bad_kb_scene_unpair_done_on_enter(void* context) {
BadKbApp* bad_kb = context;
Popup* popup = bad_kb->popup;
bad_kb_hid_ble_remove_pairing();
popup_set_icon(popup, 48, 4, &I_DolphinDone_80x58);
popup_set_header(popup, "Done", 20, 19, AlignLeft, AlignBottom);
popup_set_callback(popup, bad_kb_scene_unpair_done_popup_callback);
popup_set_context(popup, bad_kb);
popup_set_timeout(popup, 1500);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewPopup);
}
bool bad_kb_scene_unpair_done_on_event(void* context, SceneManagerEvent event) {
BadKbApp* bad_kb = context;
UNUSED(bad_kb);
UNUSED(event);
bool consumed = false;
return consumed;
}
void bad_kb_scene_unpair_done_on_exit(void* context) {
BadKbApp* bad_kb = context;
Popup* popup = bad_kb->popup;
UNUSED(popup);
popup_reset(popup);
}

View File

@@ -1,90 +0,0 @@
#include "../helpers/ducky_script.h"
#include "../bad_kb_app_i.h"
#include "../views/bad_kb_view.h"
#include <furi_hal.h>
#include "toolbox/path.h"
void bad_kb_scene_work_button_callback(InputKey key, void* context) {
furi_assert(context);
BadKbApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, key);
}
bool bad_kb_scene_work_on_event(void* context, SceneManagerEvent event) {
BadKbApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == InputKeyLeft) {
if(bad_kb_view_is_idle_state(app->bad_kb_view)) {
bad_kb_script_close(app->bad_kb_script);
app->bad_kb_script = NULL;
scene_manager_next_scene(app->scene_manager, BadKbSceneConfig);
}
consumed = true;
} else if(event.event == InputKeyOk) {
bad_kb_script_start_stop(app->bad_kb_script);
consumed = true;
} else if(event.event == InputKeyRight) {
if(bad_kb_view_is_idle_state(app->bad_kb_view)) {
bad_kb_set_interface(
app,
app->interface == BadKbHidInterfaceBle ? BadKbHidInterfaceUsb :
BadKbHidInterfaceBle);
bad_kb_script_close(app->bad_kb_script);
app->bad_kb_script = bad_kb_script_open(
app->file_path, &app->interface, &app->script_hid_cfg, false);
bad_kb_script_set_keyboard_layout(app->bad_kb_script, app->keyboard_layout);
} else {
bad_kb_script_pause_resume(app->bad_kb_script);
}
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
bad_kb_view_set_state(app->bad_kb_view, bad_kb_script_get_state(app->bad_kb_script));
bad_kb_view_set_interface(app->bad_kb_view, app->interface);
}
return consumed;
}
void bad_kb_scene_work_on_enter(void* context) {
BadKbApp* app = context;
bad_kb_view_set_interface(app->bad_kb_view, app->interface);
// Opening script the first time:
// - copy user settings as base config
// - load ID/BLE_ID/BT_ID config if present
// Then disable this until next script selected so user can customize options
bool first_script_load = scene_manager_get_scene_state(app->scene_manager, BadKbSceneWork);
if(first_script_load) {
memcpy(&app->script_hid_cfg, &app->user_hid_cfg, sizeof(app->script_hid_cfg));
scene_manager_set_scene_state(app->scene_manager, BadKbSceneWork, false);
}
// Interface and config are passed as pointers as ID/BLE_ID/BT_ID config can modify them
app->bad_kb_script = bad_kb_script_open(
app->file_path, &app->interface, &app->script_hid_cfg, first_script_load);
bad_kb_script_set_keyboard_layout(app->bad_kb_script, app->keyboard_layout);
FuriString* file_name;
file_name = furi_string_alloc();
path_extract_filename(app->file_path, file_name, true);
bad_kb_view_set_file_name(app->bad_kb_view, furi_string_get_cstr(file_name));
furi_string_free(file_name);
FuriString* layout;
layout = furi_string_alloc();
path_extract_filename(app->keyboard_layout, layout, true);
bad_kb_view_set_layout(app->bad_kb_view, furi_string_get_cstr(layout));
furi_string_free(layout);
bad_kb_view_set_state(app->bad_kb_view, bad_kb_script_get_state(app->bad_kb_script));
bad_kb_view_set_button_callback(app->bad_kb_view, bad_kb_scene_work_button_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, BadKbAppViewWork);
}
void bad_kb_scene_work_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -1,25 +0,0 @@
#pragma once
#include <gui/view.h>
#include "../helpers/ducky_script.h"
typedef struct BadKb BadKb;
typedef void (*BadKbButtonCallback)(InputKey key, void* context);
BadKb* bad_kb_view_alloc(void);
void bad_kb_view_free(BadKb* bad_kb);
View* bad_kb_view_get_view(BadKb* bad_kb);
void bad_kb_view_set_button_callback(BadKb* bad_kb, BadKbButtonCallback callback, void* context);
void bad_kb_view_set_file_name(BadKb* bad_kb, const char* name);
void bad_kb_view_set_layout(BadKb* bad_kb, const char* layout);
void bad_kb_view_set_state(BadKb* bad_kb, BadKbState* st);
void bad_kb_view_set_interface(BadKb* bad_kb, BadKbHidInterface interface);
bool bad_kb_view_is_idle_state(BadKb* bad_kb);

View File

@@ -1,10 +1,12 @@
App(
appid="bad_kb",
# Still called Bad KB for historic reasons
# Code was renamed back to Bad USB for easier update merging
name="Bad KB",
apptype=FlipperAppType.MENUEXTERNAL,
entry_point="bad_kb_app",
entry_point="bad_usb_app",
stack_size=2 * 1024,
icon="A_BadKb_14",
icon="A_BadUsb_14",
order=70,
resources="resources",
fap_icon="icon.png",

View File

@@ -1,47 +1,47 @@
#include "bad_kb_app_i.h"
#include "bad_usb_app_i.h"
#include <furi.h>
#include <furi_hal.h>
#include <storage/storage.h>
#include <lib/toolbox/path.h>
#include <flipper_format/flipper_format.h>
#define BAD_KB_SETTINGS_PATH BAD_KB_APP_BASE_FOLDER "/.badkb.settings"
#define BAD_KB_SETTINGS_FILE_TYPE "Flipper BadKB Settings File"
#define BAD_KB_SETTINGS_VERSION 1
#define BAD_KB_SETTINGS_DEFAULT_LAYOUT BAD_KB_APP_PATH_LAYOUT_FOLDER "/en-US.kl"
#define BAD_USB_SETTINGS_PATH BAD_USB_APP_BASE_FOLDER "/.badkb.settings"
#define BAD_USB_SETTINGS_FILE_TYPE "Flipper BadUSB Settings File"
#define BAD_USB_SETTINGS_VERSION 1
#define BAD_USB_SETTINGS_DEFAULT_LAYOUT BAD_USB_APP_PATH_LAYOUT_FOLDER "/en-US.kl"
static bool bad_kb_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);
BadKbApp* app = context;
BadUsbApp* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}
static bool bad_kb_app_back_event_callback(void* context) {
static bool bad_usb_app_back_event_callback(void* context) {
furi_assert(context);
BadKbApp* app = context;
BadUsbApp* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}
static void bad_kb_app_tick_event_callback(void* context) {
static void bad_usb_app_tick_event_callback(void* context) {
furi_assert(context);
BadKbApp* app = context;
BadUsbApp* app = context;
scene_manager_handle_tick_event(app->scene_manager);
}
static void bad_kb_load_settings(BadKbApp* app) {
static void bad_usb_load_settings(BadUsbApp* app) {
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff = flipper_format_file_alloc(storage);
bool loaded = false;
BadKbHidConfig* hid_cfg = &app->user_hid_cfg;
BadUsbHidConfig* hid_cfg = &app->user_hid_cfg;
FuriString* temp_str = furi_string_alloc();
uint32_t temp_uint = 0;
if(flipper_format_file_open_existing(fff, BAD_KB_SETTINGS_PATH)) {
if(flipper_format_file_open_existing(fff, BAD_USB_SETTINGS_PATH)) {
do {
if(!flipper_format_read_header(fff, temp_str, &temp_uint)) break;
if((strcmp(furi_string_get_cstr(temp_str), BAD_KB_SETTINGS_FILE_TYPE) != 0) ||
(temp_uint != BAD_KB_SETTINGS_VERSION))
if((strcmp(furi_string_get_cstr(temp_str), BAD_USB_SETTINGS_FILE_TYPE) != 0) ||
(temp_uint != BAD_USB_SETTINGS_VERSION))
break;
if(flipper_format_read_string(fff, "layout", temp_str)) {
@@ -50,16 +50,16 @@ static void bad_kb_load_settings(BadKbApp* app) {
FS_Error file_check_err = storage_common_stat(
storage, furi_string_get_cstr(app->keyboard_layout), &layout_file_info);
if((file_check_err != FSE_OK) || (layout_file_info.size != 256)) {
furi_string_set(app->keyboard_layout, BAD_KB_SETTINGS_DEFAULT_LAYOUT);
furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT);
}
} else {
furi_string_set(app->keyboard_layout, BAD_KB_SETTINGS_DEFAULT_LAYOUT);
furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT);
flipper_format_rewind(fff);
}
if(!flipper_format_read_uint32(fff, "interface", &temp_uint, 1) ||
temp_uint >= BadKbHidInterfaceMAX) {
temp_uint = BadKbHidInterfaceUsb;
temp_uint >= BadUsbHidInterfaceMAX) {
temp_uint = BadUsbHidInterfaceUsb;
flipper_format_rewind(fff);
}
app->interface = temp_uint;
@@ -130,8 +130,8 @@ static void bad_kb_load_settings(BadKbApp* app) {
furi_record_close(RECORD_STORAGE);
if(!loaded) {
furi_string_set(app->keyboard_layout, BAD_KB_SETTINGS_DEFAULT_LAYOUT);
app->interface = BadKbHidInterfaceUsb;
furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT);
app->interface = BadUsbHidInterfaceUsb;
hid_cfg->ble.bonding = true;
hid_cfg->ble.pairing = GapPairingPinCodeVerifyYesNo;
hid_cfg->ble.name[0] = '\0';
@@ -143,16 +143,16 @@ static void bad_kb_load_settings(BadKbApp* app) {
}
}
static void bad_kb_save_settings(BadKbApp* app) {
static void bad_usb_save_settings(BadUsbApp* app) {
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff = flipper_format_file_alloc(storage);
BadKbHidConfig* hid_cfg = &app->user_hid_cfg;
BadUsbHidConfig* hid_cfg = &app->user_hid_cfg;
uint32_t temp_uint = 0;
if(flipper_format_file_open_always(fff, BAD_KB_SETTINGS_PATH)) {
if(flipper_format_file_open_always(fff, BAD_USB_SETTINGS_PATH)) {
do {
if(!flipper_format_write_header_cstr(
fff, BAD_KB_SETTINGS_FILE_TYPE, BAD_KB_SETTINGS_VERSION))
fff, BAD_USB_SETTINGS_FILE_TYPE, BAD_USB_SETTINGS_VERSION))
break;
if(!flipper_format_write_string(fff, "layout", app->keyboard_layout)) break;
temp_uint = app->interface;
@@ -175,26 +175,26 @@ static void bad_kb_save_settings(BadKbApp* app) {
furi_record_close(RECORD_STORAGE);
}
void bad_kb_set_interface(BadKbApp* app, BadKbHidInterface interface) {
void bad_usb_set_interface(BadUsbApp* app, BadUsbHidInterface interface) {
app->interface = interface;
bad_kb_view_set_interface(app->bad_kb_view, interface);
bad_usb_view_set_interface(app->bad_usb_view, interface);
}
void bad_kb_app_show_loading_popup(BadKbApp* app, bool show) {
void bad_usb_app_show_loading_popup(BadUsbApp* app, bool show) {
if(show) {
// Raise timer priority so that animations can play
furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated);
view_dispatcher_switch_to_view(app->view_dispatcher, BadKbAppViewLoading);
view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewLoading);
} else {
// Restore default timer priority
furi_timer_set_thread_priority(FuriTimerThreadPriorityNormal);
}
}
BadKbApp* bad_kb_app_alloc(char* arg) {
BadKbApp* app = malloc(sizeof(BadKbApp));
BadUsbApp* bad_usb_app_alloc(char* arg) {
BadUsbApp* app = malloc(sizeof(BadUsbApp));
app->bad_kb_script = NULL;
app->bad_usb_script = NULL;
app->file_path = furi_string_alloc();
app->keyboard_layout = furi_string_alloc();
@@ -202,99 +202,101 @@ BadKbApp* bad_kb_app_alloc(char* arg) {
furi_string_set(app->file_path, arg);
}
bad_kb_load_settings(app);
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);
app->view_dispatcher = view_dispatcher_alloc();
app->scene_manager = scene_manager_alloc(&bad_kb_scene_handlers, app);
app->scene_manager = scene_manager_alloc(&bad_usb_scene_handlers, app);
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_tick_event_callback(
app->view_dispatcher, bad_kb_app_tick_event_callback, 250);
app->view_dispatcher, bad_usb_app_tick_event_callback, 250);
view_dispatcher_set_custom_event_callback(
app->view_dispatcher, bad_kb_app_custom_event_callback);
app->view_dispatcher, bad_usb_app_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher, bad_kb_app_back_event_callback);
app->view_dispatcher, bad_usb_app_back_event_callback);
// Custom Widget
app->widget = widget_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadKbAppViewWidget, widget_get_view(app->widget));
app->view_dispatcher, BadUsbAppViewWidget, widget_get_view(app->widget));
// Popup
app->popup = popup_alloc();
view_dispatcher_add_view(app->view_dispatcher, BadKbAppViewPopup, popup_get_view(app->popup));
view_dispatcher_add_view(app->view_dispatcher, BadUsbAppViewPopup, popup_get_view(app->popup));
app->var_item_list = variable_item_list_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadKbAppViewConfig, variable_item_list_get_view(app->var_item_list));
app->view_dispatcher,
BadUsbAppViewConfig,
variable_item_list_get_view(app->var_item_list));
app->bad_kb_view = bad_kb_view_alloc();
app->bad_usb_view = bad_usb_view_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadKbAppViewWork, bad_kb_view_get_view(app->bad_kb_view));
app->view_dispatcher, BadUsbAppViewWork, bad_usb_view_get_view(app->bad_usb_view));
app->text_input = text_input_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadKbAppViewTextInput, text_input_get_view(app->text_input));
app->view_dispatcher, BadUsbAppViewTextInput, text_input_get_view(app->text_input));
app->byte_input = byte_input_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadKbAppViewByteInput, byte_input_get_view(app->byte_input));
app->view_dispatcher, BadUsbAppViewByteInput, byte_input_get_view(app->byte_input));
app->loading = loading_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadKbAppViewLoading, loading_get_view(app->loading));
app->view_dispatcher, BadUsbAppViewLoading, loading_get_view(app->loading));
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
if(!furi_string_empty(app->file_path)) {
scene_manager_set_scene_state(app->scene_manager, BadKbSceneWork, true);
scene_manager_next_scene(app->scene_manager, BadKbSceneWork);
scene_manager_set_scene_state(app->scene_manager, BadUsbSceneWork, true);
scene_manager_next_scene(app->scene_manager, BadUsbSceneWork);
} else {
furi_string_set(app->file_path, BAD_KB_APP_BASE_FOLDER);
scene_manager_next_scene(app->scene_manager, BadKbSceneFileSelect);
furi_string_set(app->file_path, BAD_USB_APP_BASE_FOLDER);
scene_manager_next_scene(app->scene_manager, BadUsbSceneFileSelect);
}
return app;
}
void bad_kb_app_free(BadKbApp* app) {
void bad_usb_app_free(BadUsbApp* app) {
furi_assert(app);
if(app->bad_kb_script) {
bad_kb_script_close(app->bad_kb_script);
app->bad_kb_script = NULL;
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, BadKbAppViewWork);
bad_kb_view_free(app->bad_kb_view);
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork);
bad_usb_view_free(app->bad_usb_view);
// Custom Widget
view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewWidget);
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWidget);
widget_free(app->widget);
// Popup
view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewPopup);
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewPopup);
popup_free(app->popup);
// Config menu
view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewConfig);
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig);
variable_item_list_free(app->var_item_list);
// Text Input
view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewTextInput);
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewTextInput);
text_input_free(app->text_input);
// Byte Input
view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewByteInput);
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewByteInput);
byte_input_free(app->byte_input);
// Loading
view_dispatcher_remove_view(app->view_dispatcher, BadKbAppViewLoading);
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewLoading);
loading_free(app->loading);
// View dispatcher
@@ -306,7 +308,7 @@ void bad_kb_app_free(BadKbApp* app) {
furi_record_close(RECORD_NOTIFICATION);
furi_record_close(RECORD_DIALOGS);
bad_kb_save_settings(app);
bad_usb_save_settings(app);
furi_string_free(app->file_path);
furi_string_free(app->keyboard_layout);
@@ -314,11 +316,11 @@ void bad_kb_app_free(BadKbApp* app) {
free(app);
}
int32_t bad_kb_app(void* p) {
BadKbApp* bad_kb_app = bad_kb_app_alloc((char*)p);
int32_t bad_usb_app(void* p) {
BadUsbApp* bad_usb_app = bad_usb_app_alloc((char*)p);
view_dispatcher_run(bad_kb_app->view_dispatcher);
view_dispatcher_run(bad_usb_app->view_dispatcher);
bad_kb_app_free(bad_kb_app);
bad_usb_app_free(bad_usb_app);
return 0;
}

View File

@@ -4,7 +4,7 @@
extern "C" {
#endif
typedef struct BadKbApp BadKbApp;
typedef struct BadUsbApp BadUsbApp;
#ifdef __cplusplus
}

View File

@@ -1,9 +1,9 @@
#pragma once
#include "bad_kb_app.h"
#include "scenes/bad_kb_scene.h"
#include "bad_usb_app.h"
#include "scenes/bad_usb_scene.h"
#include "helpers/ducky_script.h"
#include "helpers/bad_kb_hid.h"
#include "helpers/bad_usb_hid.h"
#include <gui/gui.h>
#include <assets_icons.h>
@@ -17,19 +17,19 @@
#include <gui/modules/loading.h>
#include <gui/modules/widget.h>
#include <gui/modules/popup.h>
#include "views/bad_kb_view.h"
#include "views/bad_usb_view.h"
#include <furi_hal_usb.h>
#define BAD_KB_APP_BASE_FOLDER EXT_PATH("badusb")
#define BAD_KB_APP_PATH_LAYOUT_FOLDER BAD_KB_APP_BASE_FOLDER "/assets/layouts"
#define BAD_KB_APP_SCRIPT_EXTENSION ".txt"
#define BAD_KB_APP_LAYOUT_EXTENSION ".kl"
#define BAD_USB_APP_BASE_FOLDER EXT_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 {
BadKbAppErrorNoFiles,
} BadKbAppError;
BadUsbAppErrorNoFiles,
} BadUsbAppError;
struct BadKbApp {
struct BadUsbApp {
Gui* gui;
ViewDispatcher* view_dispatcher;
SceneManager* scene_manager;
@@ -47,27 +47,27 @@ struct BadKbApp {
char usb_name_buf[HID_MANUF_PRODUCT_NAME_LEN];
uint16_t usb_vidpid_buf[2];
BadKbAppError error;
BadUsbAppError error;
FuriString* file_path;
FuriString* keyboard_layout;
BadKb* bad_kb_view;
BadKbScript* bad_kb_script;
BadUsb* bad_usb_view;
BadUsbScript* bad_usb_script;
BadKbHidInterface interface;
BadKbHidConfig user_hid_cfg;
BadKbHidConfig script_hid_cfg;
BadUsbHidInterface interface;
BadUsbHidConfig user_hid_cfg;
BadUsbHidConfig script_hid_cfg;
};
typedef enum {
BadKbAppViewWidget,
BadKbAppViewPopup,
BadKbAppViewWork,
BadKbAppViewConfig,
BadKbAppViewByteInput,
BadKbAppViewTextInput,
BadKbAppViewLoading,
} BadKbAppView;
BadUsbAppViewWidget,
BadUsbAppViewPopup,
BadUsbAppViewWork,
BadUsbAppViewConfig,
BadUsbAppViewByteInput,
BadUsbAppViewTextInput,
BadUsbAppViewLoading,
} BadUsbAppView;
void bad_kb_set_interface(BadKbApp* app, BadKbHidInterface interface);
void bad_usb_set_interface(BadUsbApp* app, BadUsbHidInterface interface);
void bad_kb_app_show_loading_popup(BadKbApp* app, bool show);
void bad_usb_app_show_loading_popup(BadUsbApp* app, bool show);

View File

@@ -1,19 +1,19 @@
#include "bad_kb_hid.h"
#include "bad_usb_hid.h"
#include "ble_hid_profile.h"
#include <bt/bt_service/bt.h>
#include <bt/bt_service/bt_i.h>
#include <storage/storage.h>
#define TAG "BadKB HID"
#define TAG "BadUSB HID"
#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys"
void hid_usb_adjust_config(BadKbHidConfig* hid_cfg) {
void hid_usb_adjust_config(BadUsbHidConfig* hid_cfg) {
if(hid_cfg->usb.vid == 0) hid_cfg->usb.vid = HID_VID_DEFAULT;
if(hid_cfg->usb.pid == 0) hid_cfg->usb.pid = HID_PID_DEFAULT;
}
void* hid_usb_init(BadKbHidConfig* hid_cfg) {
void* hid_usb_init(BadUsbHidConfig* hid_cfg) {
FuriHalUsbInterface* usb_if_prev = furi_hal_usb_get_config();
furi_hal_usb_unlock();
hid_usb_adjust_config(hid_cfg);
@@ -94,7 +94,7 @@ uint8_t hid_usb_get_led_state(void* inst) {
return furi_hal_hid_get_led_state();
}
static const BadKbHidApi hid_api_usb = {
static const BadUsbHidApi hid_api_usb = {
.adjust_config = hid_usb_adjust_config,
.init = hid_usb_init,
.deinit = hid_usb_deinit,
@@ -130,29 +130,29 @@ static void hid_ble_connection_status_callback(BtStatus status, void* context) {
}
}
void hid_ble_adjust_config(BadKbHidConfig* hid_cfg) {
void hid_ble_adjust_config(BadUsbHidConfig* hid_cfg) {
const uint8_t* normal_mac = furi_hal_version_get_ble_mac();
uint8_t empty_mac[GAP_MAC_ADDR_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t default_mac[GAP_MAC_ADDR_SIZE] = {0x6c, 0x7a, 0xd8, 0xac, 0x57, 0x72}; // furi_hal_bt
if(memcmp(hid_cfg->ble.mac, empty_mac, sizeof(hid_cfg->ble.mac)) == 0 ||
memcmp(hid_cfg->ble.mac, normal_mac, sizeof(hid_cfg->ble.mac)) == 0 ||
memcmp(hid_cfg->ble.mac, default_mac, sizeof(hid_cfg->ble.mac)) == 0) {
// Derive badkb MAC from Flipper MAC
// Derive badusb MAC from Flipper MAC
memcpy(hid_cfg->ble.mac, normal_mac, sizeof(hid_cfg->ble.mac));
hid_cfg->ble.mac[2]++;
uint16_t badkb_mac_xor = 0x0002;
hid_cfg->ble.mac[0] ^= badkb_mac_xor;
hid_cfg->ble.mac[1] ^= badkb_mac_xor >> 8;
uint16_t badusb_mac_xor = 0x0002;
hid_cfg->ble.mac[0] ^= badusb_mac_xor;
hid_cfg->ble.mac[1] ^= badusb_mac_xor >> 8;
}
if(hid_cfg->ble.name[0] == '\0') {
// Derive badkb name from Flipper name
const char* badkb_device_name_prefix = "BadKB";
// Derive badusb name from Flipper name
const char* badusb_device_name_prefix = "BadKB";
snprintf(
hid_cfg->ble.name,
sizeof(hid_cfg->ble.name),
"%s %s",
badkb_device_name_prefix,
badusb_device_name_prefix,
furi_hal_version_get_name_ptr());
}
@@ -161,7 +161,7 @@ void hid_ble_adjust_config(BadKbHidConfig* hid_cfg) {
}
}
void* hid_ble_init(BadKbHidConfig* hid_cfg) {
void* hid_ble_init(BadUsbHidConfig* hid_cfg) {
BleHidInstance* ble_hid = malloc(sizeof(BleHidInstance));
ble_hid->bt = furi_record_open(RECORD_BT);
ble_hid->bt->suppress_pin_screen = true;
@@ -273,7 +273,7 @@ uint8_t hid_ble_get_led_state(void* inst) {
return 0;
}
static const BadKbHidApi hid_api_ble = {
static const BadUsbHidApi hid_api_ble = {
.adjust_config = hid_ble_adjust_config,
.init = hid_ble_init,
.deinit = hid_ble_deinit,
@@ -292,15 +292,15 @@ static const BadKbHidApi hid_api_ble = {
.get_led_state = hid_ble_get_led_state,
};
const BadKbHidApi* bad_kb_hid_get_interface(BadKbHidInterface interface) {
if(interface == BadKbHidInterfaceUsb) {
const BadUsbHidApi* bad_usb_hid_get_interface(BadUsbHidInterface interface) {
if(interface == BadUsbHidInterfaceUsb) {
return &hid_api_usb;
} else {
return &hid_api_ble;
}
}
void bad_kb_hid_ble_remove_pairing(void) {
void bad_usb_hid_ble_remove_pairing(void) {
Bt* bt = furi_record_open(RECORD_BT);
bt_disconnect(bt);

View File

@@ -10,19 +10,19 @@ extern "C" {
#include "ble_hid_profile.h"
typedef enum {
BadKbHidInterfaceUsb,
BadKbHidInterfaceBle,
BadKbHidInterfaceMAX,
} BadKbHidInterface;
BadUsbHidInterfaceUsb,
BadUsbHidInterfaceBle,
BadUsbHidInterfaceMAX,
} BadUsbHidInterface;
typedef struct {
BleProfileHidParams ble;
FuriHalUsbHidConfig usb;
} BadKbHidConfig;
} BadUsbHidConfig;
typedef struct {
void (*adjust_config)(BadKbHidConfig* hid_cfg);
void* (*init)(BadKbHidConfig* hid_cfg);
void (*adjust_config)(BadUsbHidConfig* hid_cfg);
void* (*init)(BadUsbHidConfig* hid_cfg);
void (*deinit)(void* inst);
void (*set_state_callback)(void* inst, HidStateCallback cb, void* context);
bool (*is_connected)(void* inst);
@@ -37,11 +37,11 @@ typedef struct {
bool (*consumer_release)(void* inst, uint16_t button);
bool (*release_all)(void* inst);
uint8_t (*get_led_state)(void* inst);
} BadKbHidApi;
} BadUsbHidApi;
const BadKbHidApi* bad_kb_hid_get_interface(BadKbHidInterface interface);
const BadUsbHidApi* bad_usb_hid_get_interface(BadUsbHidInterface interface);
void bad_kb_hid_ble_remove_pairing(void);
void bad_usb_hid_ble_remove_pairing(void);
#ifdef __cplusplus
}

View File

@@ -0,0 +1,811 @@
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include <input/input.h>
#include <lib/toolbox/args.h>
#include <lib/toolbox/strint.h>
#include <storage/storage.h>
#include "ducky_script.h"
#include "ducky_script_i.h"
#include <dolphin/dolphin.h>
#define TAG "BadUsb"
#define WORKER_TAG TAG "Worker"
#define BADUSB_ASCII_TO_KEY(script, x) \
(((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE)
typedef enum {
WorkerEvtStartStop = (1 << 0),
WorkerEvtPauseResume = (1 << 1),
WorkerEvtEnd = (1 << 2),
WorkerEvtConnect = (1 << 3),
WorkerEvtDisconnect = (1 << 4),
} WorkerEvtFlags;
static const char ducky_cmd_id[] = {"ID"};
static const char ducky_cmd_bt_id[] = {"BT_ID"};
static const char ducky_cmd_ble_id[] = {"BLE_ID"};
static const uint8_t numpad_keys[10] = {
HID_KEYPAD_0,
HID_KEYPAD_1,
HID_KEYPAD_2,
HID_KEYPAD_3,
HID_KEYPAD_4,
HID_KEYPAD_5,
HID_KEYPAD_6,
HID_KEYPAD_7,
HID_KEYPAD_8,
HID_KEYPAD_9,
};
uint32_t ducky_get_command_len(const char* line) {
uint32_t len = strlen(line);
for(uint32_t i = 0; i < len; i++) {
if(line[i] == ' ') return i;
}
return 0;
}
bool ducky_is_line_end(const char chr) {
return (chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n');
}
uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars) {
uint16_t keycode = ducky_get_keycode_by_name(param);
if(keycode != HID_KEYBOARD_NONE) {
return keycode;
}
if((accept_chars) && (strlen(param) > 0)) {
return BADUSB_ASCII_TO_KEY(bad_usb, param[0]) & 0xFF;
}
return 0;
}
bool ducky_get_number(const char* param, uint32_t* val) {
uint32_t value = 0;
if(strint_to_uint32(param, NULL, &value, 10) == StrintParseNoError) {
*val = value;
return true;
}
return false;
}
void ducky_numlock_on(BadUsbScript* bad_usb) {
if((bad_usb->hid->get_led_state(bad_usb->hid_inst) & HID_KB_LED_NUM) == 0) {
bad_usb->hid->kb_press(bad_usb->hid_inst, HID_KEYBOARD_LOCK_NUM_LOCK);
bad_usb->hid->kb_release(bad_usb->hid_inst, HID_KEYBOARD_LOCK_NUM_LOCK);
}
}
bool ducky_numpad_press(BadUsbScript* bad_usb, const char num) {
if((num < '0') || (num > '9')) return false;
uint16_t key = numpad_keys[num - '0'];
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
return true;
}
bool ducky_altchar(BadUsbScript* bad_usb, const char* charcode) {
uint8_t i = 0;
bool state = false;
bad_usb->hid->kb_press(bad_usb->hid_inst, KEY_MOD_LEFT_ALT);
while(!ducky_is_line_end(charcode[i])) {
state = ducky_numpad_press(bad_usb, charcode[i]);
if(state == false) break;
i++;
}
bad_usb->hid->kb_release(bad_usb->hid_inst, KEY_MOD_LEFT_ALT);
return state;
}
bool ducky_altstring(BadUsbScript* bad_usb, const char* param) {
uint32_t i = 0;
bool state = false;
while(param[i] != '\0') {
if((param[i] < ' ') || (param[i] > '~')) {
i++;
continue; // Skip non-printable chars
}
char temp_str[4];
snprintf(temp_str, 4, "%u", param[i]);
state = ducky_altchar(bad_usb, temp_str);
if(state == false) break;
i++;
}
return state;
}
int32_t ducky_error(BadUsbScript* bad_usb, const char* text, ...) {
va_list args;
va_start(args, text);
vsnprintf(bad_usb->st.error, sizeof(bad_usb->st.error), text, args);
va_end(args);
return SCRIPT_STATE_ERROR;
}
bool ducky_string(BadUsbScript* bad_usb, const char* param) {
uint32_t i = 0;
while(param[i] != '\0') {
if(param[i] != '\n') {
uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]);
if(keycode != HID_KEYBOARD_NONE) {
bad_usb->hid->kb_press(bad_usb->hid_inst, keycode);
bad_usb->hid->kb_release(bad_usb->hid_inst, keycode);
}
} else {
bad_usb->hid->kb_press(bad_usb->hid_inst, HID_KEYBOARD_RETURN);
bad_usb->hid->kb_release(bad_usb->hid_inst, HID_KEYBOARD_RETURN);
}
i++;
}
bad_usb->stringdelay = 0;
return true;
}
static bool ducky_string_next(BadUsbScript* bad_usb) {
if(bad_usb->string_print_pos >= furi_string_size(bad_usb->string_print)) {
return true;
}
char print_char = furi_string_get_char(bad_usb->string_print, bad_usb->string_print_pos);
if(print_char != '\n') {
uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, print_char);
if(keycode != HID_KEYBOARD_NONE) {
bad_usb->hid->kb_press(bad_usb->hid_inst, keycode);
bad_usb->hid->kb_release(bad_usb->hid_inst, keycode);
}
} else {
bad_usb->hid->kb_press(bad_usb->hid_inst, HID_KEYBOARD_RETURN);
bad_usb->hid->kb_release(bad_usb->hid_inst, HID_KEYBOARD_RETURN);
}
bad_usb->string_print_pos++;
return false;
}
static int32_t ducky_parse_line(BadUsbScript* bad_usb, FuriString* line) {
uint32_t line_len = furi_string_size(line);
const char* line_tmp = furi_string_get_cstr(line);
if(line_len == 0) {
return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
}
FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp);
// Ducky Lang Functions
int32_t cmd_result = ducky_execute_cmd(bad_usb, line_tmp);
if(cmd_result != SCRIPT_STATE_CMD_UNKNOWN) {
return cmd_result;
}
// Mouse Keys
uint16_t key = ducky_get_mouse_keycode_by_name(line_tmp);
if(key != HID_MOUSE_INVALID) {
bad_usb->hid->mouse_press(bad_usb->hid_inst, key);
bad_usb->hid->mouse_release(bad_usb->hid_inst, key);
return 0;
}
// Special keys + modifiers
key = ducky_get_keycode(bad_usb, line_tmp, false);
if(key == HID_KEYBOARD_NONE) {
return ducky_error(bad_usb, "No keycode defined for %s", line_tmp);
}
if((key & 0xFF00) != 0) {
// It's a modifier key
uint32_t offset = ducky_get_command_len(line_tmp) + 1;
// ducky_get_command_len() returns 0 without space, so check for != 1
if(offset != 1 && line_len > offset) {
// It's also a key combination
line_tmp = &line_tmp[offset];
key |= ducky_get_keycode(bad_usb, line_tmp, true);
}
}
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
return 0;
}
static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) {
FuriHalUsbHidConfig* usb_hid_cfg = &bad_usb->hid_cfg->usb;
if(sscanf(line, "%lX:%lX", &usb_hid_cfg->vid, &usb_hid_cfg->pid) == 2) {
usb_hid_cfg->manuf[0] = '\0';
usb_hid_cfg->product[0] = '\0';
uint8_t id_len = ducky_get_command_len(line);
if(!ducky_is_line_end(line[id_len + 1])) {
sscanf(
&line[id_len + 1],
"%31[^\r\n:]:%31[^\r\n]",
usb_hid_cfg->manuf,
usb_hid_cfg->product);
}
FURI_LOG_D(
WORKER_TAG,
"set id: %04lX:%04lX mfr:%s product:%s",
usb_hid_cfg->vid,
usb_hid_cfg->pid,
usb_hid_cfg->manuf,
usb_hid_cfg->product);
return true;
}
return false;
}
static bool ducky_set_ble_id(BadUsbScript* bad_usb, const char* line) {
BleProfileHidParams* ble_hid_cfg = &bad_usb->hid_cfg->ble;
size_t line_len = strlen(line);
size_t mac_len = sizeof(ble_hid_cfg->mac) * 3; // 2 hex chars + separator per byte
if(line_len < mac_len + 1) return false; // MAC + at least 1 char for name
for(size_t i = 0; i < sizeof(ble_hid_cfg->mac); i++) {
const char* hex_byte = &line[i * 3];
// This sscanf() doesn't work well with %02hhX, need to use a u32
uint32_t temp_uint;
if(sscanf(hex_byte, "%02lX", &temp_uint) != 1) {
return false;
}
ble_hid_cfg->mac[sizeof(ble_hid_cfg->mac) - 1 - i] = temp_uint;
}
strlcpy(ble_hid_cfg->name, line + mac_len, sizeof(ble_hid_cfg->name));
FURI_LOG_D(WORKER_TAG, "set ble id: %s", line);
return true;
}
static void bad_usb_hid_state_callback(bool state, void* context) {
furi_assert(context);
BadUsbScript* bad_usb = context;
if(state == true) {
furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect);
} else {
furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtDisconnect);
}
}
static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
uint8_t ret = 0;
uint32_t line_len = 0;
furi_string_reset(bad_usb->line);
do {
ret = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN);
for(uint16_t i = 0; i < ret; i++) {
if(bad_usb->file_buf[i] == '\n' && line_len > 0) {
bad_usb->st.line_nb++;
line_len = 0;
} else {
if(bad_usb->st.line_nb == 0) { // Save first line
furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]);
}
line_len++;
}
}
if(storage_file_eof(script_file)) {
if(line_len > 0) {
bad_usb->st.line_nb++;
break;
}
}
} while(ret > 0);
if(bad_usb->load_id_cfg) {
const char* line_tmp = furi_string_get_cstr(bad_usb->line);
BadUsbHidInterface interface = *bad_usb->interface;
// Look for ID/BLE_ID/BT_ID command on first line
if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) {
if(ducky_set_usb_id(bad_usb, &line_tmp[strlen(ducky_cmd_id) + 1])) {
interface = BadUsbHidInterfaceUsb;
}
} else if(
strncmp(line_tmp, ducky_cmd_ble_id, strlen(ducky_cmd_ble_id)) == 0 ||
strncmp(line_tmp, ducky_cmd_bt_id, strlen(ducky_cmd_bt_id)) == 0) {
if(ducky_set_ble_id(bad_usb, &line_tmp[ducky_get_command_len(line_tmp) + 1])) {
interface = BadUsbHidInterfaceBle;
}
}
// Auto-switch based on ID/BLE_ID/BT_ID command, user can override manually after
if(interface != *bad_usb->interface) {
*bad_usb->interface = interface;
bad_usb->hid = bad_usb_hid_get_interface(*bad_usb->interface);
}
}
bad_usb->hid_inst = bad_usb->hid->init(bad_usb->hid_cfg);
bad_usb->hid->set_state_callback(bad_usb->hid_inst, bad_usb_hid_state_callback, bad_usb);
storage_file_seek(script_file, 0, true);
furi_string_reset(bad_usb->line);
return true;
}
static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_file) {
int32_t delay_val = 0;
if(bad_usb->repeat_cnt > 0) {
bad_usb->repeat_cnt--;
delay_val = ducky_parse_line(bad_usb, bad_usb->line_prev);
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
return 0;
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
return delay_val;
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
return delay_val;
} else if(delay_val < 0) { // Script error
bad_usb->st.error_line = bad_usb->st.line_cur - 1;
FURI_LOG_E(WORKER_TAG, "Unknown command at line %zu", bad_usb->st.line_cur - 1U);
return SCRIPT_STATE_ERROR;
} else {
return delay_val + bad_usb->defdelay;
}
}
furi_string_set(bad_usb->line_prev, bad_usb->line);
furi_string_reset(bad_usb->line);
while(1) {
if(bad_usb->buf_len == 0) {
bad_usb->buf_len = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN);
if(storage_file_eof(script_file)) {
if((bad_usb->buf_len < FILE_BUFFER_LEN) && (bad_usb->file_end == false)) {
bad_usb->file_buf[bad_usb->buf_len] = '\n';
bad_usb->buf_len++;
bad_usb->file_end = true;
}
}
bad_usb->buf_start = 0;
if(bad_usb->buf_len == 0) return SCRIPT_STATE_END;
}
for(uint8_t i = bad_usb->buf_start; i < (bad_usb->buf_start + bad_usb->buf_len); i++) {
if(bad_usb->file_buf[i] == '\n' && furi_string_size(bad_usb->line) > 0) {
bad_usb->st.line_cur++;
bad_usb->buf_len = bad_usb->buf_len + bad_usb->buf_start - (i + 1);
bad_usb->buf_start = i + 1;
furi_string_trim(bad_usb->line);
delay_val = ducky_parse_line(bad_usb, bad_usb->line);
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
return 0;
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
return delay_val;
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
return delay_val;
} else if(delay_val < 0) {
bad_usb->st.error_line = bad_usb->st.line_cur;
FURI_LOG_E(WORKER_TAG, "Unknown command at line %zu", bad_usb->st.line_cur);
return SCRIPT_STATE_ERROR;
} else {
return delay_val + bad_usb->defdelay;
}
} else {
furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]);
}
}
bad_usb->buf_len = 0;
if(bad_usb->file_end) return SCRIPT_STATE_END;
}
return 0;
}
static uint32_t bad_usb_flags_get(uint32_t flags_mask, uint32_t timeout) {
uint32_t flags = furi_thread_flags_get();
furi_check((flags & FuriFlagError) == 0);
if(flags == 0) {
flags = furi_thread_flags_wait(flags_mask, FuriFlagWaitAny, timeout);
furi_check(((flags & FuriFlagError) == 0) || (flags == (unsigned)FuriFlagErrorTimeout));
} else {
uint32_t state = furi_thread_flags_clear(flags);
furi_check((state & FuriFlagError) == 0);
}
return flags;
}
static int32_t bad_usb_worker(void* context) {
BadUsbScript* bad_usb = context;
BadUsbWorkerState worker_state = BadUsbStateInit;
BadUsbWorkerState pause_state = BadUsbStateRunning;
int32_t delay_val = 0;
FURI_LOG_I(WORKER_TAG, "Init");
File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
bad_usb->line = furi_string_alloc();
bad_usb->line_prev = furi_string_alloc();
bad_usb->string_print = furi_string_alloc();
bad_usb->st.elapsed = 0;
while(1) {
uint32_t start = furi_get_tick();
if(worker_state == BadUsbStateInit) { // State: initialization
start = 0;
FURI_LOG_D(WORKER_TAG, "init start");
if(storage_file_open(
script_file,
furi_string_get_cstr(bad_usb->file_path),
FSAM_READ,
FSOM_OPEN_EXISTING)) {
if((ducky_script_preload(bad_usb, script_file)) && (bad_usb->st.line_nb > 0)) {
if(bad_usb->hid->is_connected(bad_usb->hid_inst)) {
worker_state = BadUsbStateIdle; // Ready to run
} else {
worker_state = BadUsbStateNotConnected; // USB not connected
}
} else {
worker_state = BadUsbStateScriptError; // Script preload error
}
} else {
FURI_LOG_E(WORKER_TAG, "File open error");
worker_state = BadUsbStateFileError; // File open error
}
bad_usb->st.state = worker_state;
FURI_LOG_D(WORKER_TAG, "init done");
} else if(worker_state == BadUsbStateNotConnected) { // State: Not connected
start = 0;
FURI_LOG_D(WORKER_TAG, "not connected wait");
uint32_t flags = bad_usb_flags_get(
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop,
FuriWaitForever);
FURI_LOG_D(WORKER_TAG, "not connected flags: %lu", flags);
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtConnect) {
worker_state = BadUsbStateIdle; // Ready to run
} else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateWillRun; // Will run when connected
}
bad_usb->st.state = worker_state;
} else if(worker_state == BadUsbStateIdle) { // State: ready to start
start = 0;
FURI_LOG_D(WORKER_TAG, "idle wait");
uint32_t flags = bad_usb_flags_get(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtDisconnect, FuriWaitForever);
FURI_LOG_D(WORKER_TAG, "idle flags: %lu", flags);
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) { // Start executing script
dolphin_deed(DolphinDeedBadUsbPlayScript);
delay_val = 0;
bad_usb->buf_len = 0;
bad_usb->st.line_cur = 0;
bad_usb->defdelay = 0;
bad_usb->stringdelay = 0;
bad_usb->defstringdelay = 0;
bad_usb->repeat_cnt = 0;
bad_usb->key_hold_nb = 0;
bad_usb->file_end = false;
storage_file_seek(script_file, 0, true);
worker_state = BadUsbStateRunning;
bad_usb->st.elapsed = 0;
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // Disconnected
}
bad_usb->st.state = worker_state;
} else if(worker_state == BadUsbStateWillRun) { // State: start on connection
start = 0;
FURI_LOG_D(WORKER_TAG, "will run wait");
uint32_t flags = bad_usb_flags_get(
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtStartStop, FuriWaitForever);
FURI_LOG_D(WORKER_TAG, "will run flags: %lu", flags);
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtConnect) { // Start executing script
dolphin_deed(DolphinDeedBadUsbPlayScript);
delay_val = 0;
bad_usb->buf_len = 0;
bad_usb->st.line_cur = 0;
bad_usb->defdelay = 0;
bad_usb->stringdelay = 0;
bad_usb->defstringdelay = 0;
bad_usb->repeat_cnt = 0;
bad_usb->file_end = false;
storage_file_seek(script_file, 0, true);
// extra time for PC to recognize Flipper as keyboard
flags = furi_thread_flags_wait(
WorkerEvtEnd | WorkerEvtDisconnect | WorkerEvtStartStop,
FuriFlagWaitAny | FuriFlagNoClear,
1500);
if(flags == (unsigned)FuriFlagErrorTimeout) {
// If nothing happened - start script execution
worker_state = BadUsbStateRunning;
bad_usb->st.elapsed = 0;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateIdle;
furi_thread_flags_clear(WorkerEvtStartStop);
}
} else if(flags & WorkerEvtStartStop) { // Cancel scheduled execution
worker_state = BadUsbStateNotConnected;
}
bad_usb->st.state = worker_state;
} else if(worker_state == BadUsbStateRunning) { // State: running
FURI_LOG_D(WORKER_TAG, "running");
uint16_t delay_cur = (delay_val > 100) ? (100) : (delay_val);
uint32_t flags = furi_thread_flags_wait(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect,
FuriFlagWaitAny,
delay_cur);
FURI_LOG_D(WORKER_TAG, "running flags: %lu", flags);
delay_val -= delay_cur;
if(!(flags & FuriFlagError)) {
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateIdle; // Stop executing script
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // Disconnected
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
pause_state = BadUsbStateRunning;
worker_state = BadUsbStatePaused; // Pause
}
bad_usb->st.state = worker_state;
bad_usb->st.elapsed += (furi_get_tick() - start);
continue;
} else if(
(flags == (unsigned)FuriFlagErrorTimeout) ||
(flags == (unsigned)FuriFlagErrorResource)) {
if(delay_val > 0) {
bad_usb->st.delay_remain--;
bad_usb->st.elapsed += (furi_get_tick() - start);
continue;
}
bad_usb->st.state = BadUsbStateRunning;
delay_val = ducky_script_execute_next(bad_usb, script_file);
if(delay_val == SCRIPT_STATE_ERROR) { // Script error
delay_val = 0;
worker_state = BadUsbStateScriptError;
bad_usb->st.state = worker_state;
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(delay_val == SCRIPT_STATE_END) { // End of script
delay_val = 0;
worker_state = BadUsbStateIdle;
bad_usb->st.state = BadUsbStateDone;
bad_usb->hid->release_all(bad_usb->hid_inst);
bad_usb->st.elapsed += (furi_get_tick() - start);
continue;
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays
delay_val = bad_usb->defdelay;
bad_usb->string_print_pos = 0;
worker_state = BadUsbStateStringDelay;
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // set state to wait for user input
worker_state = BadUsbStateWaitForBtn;
bad_usb->st.state = BadUsbStateWaitForBtn; // Show long delays
} else if(delay_val > 100) {
bad_usb->st.state = BadUsbStateDelay; // Show long delays
bad_usb->st.delay_remain = delay_val / 100;
}
} else {
furi_check((flags & FuriFlagError) == 0);
}
} else if(worker_state == BadUsbStateWaitForBtn) { // State: Wait for button Press
start = 0;
FURI_LOG_D(WORKER_TAG, "button wait");
uint32_t flags = bad_usb_flags_get(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect,
FuriWaitForever);
FURI_LOG_D(WORKER_TAG, "button flags: %lu", flags);
if(!(flags & FuriFlagError)) {
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) {
delay_val = 0;
worker_state = BadUsbStateRunning;
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // Disconnected
bad_usb->hid->release_all(bad_usb->hid_inst);
}
bad_usb->st.state = worker_state;
continue;
}
} else if(worker_state == BadUsbStatePaused) { // State: Paused
start = 0;
FURI_LOG_D(WORKER_TAG, "paused wait");
uint32_t flags = bad_usb_flags_get(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect,
FuriWaitForever);
FURI_LOG_D(WORKER_TAG, "paused flags: %lu", flags);
if(!(flags & FuriFlagError)) {
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateIdle; // Stop executing script
bad_usb->st.state = worker_state;
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // Disconnected
bad_usb->st.state = worker_state;
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
if(pause_state == BadUsbStateRunning) {
if(delay_val > 0) {
bad_usb->st.state = BadUsbStateDelay;
bad_usb->st.delay_remain = delay_val / 100;
} else {
bad_usb->st.state = BadUsbStateRunning;
delay_val = 0;
}
worker_state = BadUsbStateRunning; // Resume
} else if(pause_state == BadUsbStateStringDelay) {
bad_usb->st.state = BadUsbStateRunning;
worker_state = BadUsbStateStringDelay; // Resume
}
}
continue;
}
} else if(worker_state == BadUsbStateStringDelay) { // State: print string with delays
FURI_LOG_D(WORKER_TAG, "delay wait");
uint32_t delay = (bad_usb->stringdelay == 0) ? bad_usb->defstringdelay :
bad_usb->stringdelay;
uint32_t flags = bad_usb_flags_get(
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtDisconnect,
delay);
FURI_LOG_D(WORKER_TAG, "delay flags: %lu", flags);
if(!(flags & FuriFlagError)) {
if(flags & WorkerEvtEnd) {
break;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateIdle; // Stop executing script
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // Disconnected
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
pause_state = BadUsbStateStringDelay;
worker_state = BadUsbStatePaused; // Pause
}
bad_usb->st.state = worker_state;
bad_usb->st.elapsed += (furi_get_tick() - start);
continue;
} else if(
(flags == (unsigned)FuriFlagErrorTimeout) ||
(flags == (unsigned)FuriFlagErrorResource)) {
bool string_end = ducky_string_next(bad_usb);
if(string_end) {
bad_usb->stringdelay = 0;
worker_state = BadUsbStateRunning;
}
} else {
furi_check((flags & FuriFlagError) == 0);
}
} else if(
(worker_state == BadUsbStateFileError) ||
(worker_state == BadUsbStateScriptError)) { // State: error
start = 0;
FURI_LOG_D(WORKER_TAG, "error wait");
uint32_t flags =
bad_usb_flags_get(WorkerEvtEnd, FuriWaitForever); // Waiting for exit command
FURI_LOG_D(WORKER_TAG, "error flags: %lu", flags);
if(flags & WorkerEvtEnd) {
break;
}
}
if(start) {
bad_usb->st.elapsed += (furi_get_tick() - start);
}
}
bad_usb->hid->set_state_callback(bad_usb->hid_inst, NULL, NULL);
bad_usb->hid->deinit(bad_usb->hid_inst);
storage_file_close(script_file);
storage_file_free(script_file);
furi_string_free(bad_usb->line);
furi_string_free(bad_usb->line_prev);
furi_string_free(bad_usb->string_print);
FURI_LOG_I(WORKER_TAG, "End");
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,
BadUsbHidInterface* interface,
BadUsbHidConfig* hid_cfg,
bool load_id_cfg) {
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';
bad_usb->interface = interface;
bad_usb->hid_cfg = hid_cfg;
bad_usb->load_id_cfg = load_id_cfg;
bad_usb->hid = bad_usb_hid_get_interface(*bad_usb->interface);
bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb);
furi_thread_start(bad_usb->thread);
return bad_usb;
} //-V773
void bad_usb_script_close(BadUsbScript* bad_usb) {
furi_assert(bad_usb);
furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtEnd);
furi_thread_join(bad_usb->thread);
furi_thread_free(bad_usb->thread);
furi_string_free(bad_usb->file_path);
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)) { //-V1051
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_start_stop(BadUsbScript* bad_usb) {
furi_assert(bad_usb);
furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtStartStop);
}
void bad_usb_script_pause_resume(BadUsbScript* bad_usb) {
furi_assert(bad_usb);
furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtPauseResume);
}
BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb) {
furi_assert(bad_usb);
return &(bad_usb->st);
}

View File

@@ -0,0 +1,60 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <furi.h>
#include <furi_hal.h>
#include "bad_usb_hid.h"
typedef enum {
BadUsbStateInit,
BadUsbStateNotConnected,
BadUsbStateIdle,
BadUsbStateWillRun,
BadUsbStateRunning,
BadUsbStateDelay,
BadUsbStateStringDelay,
BadUsbStateWaitForBtn,
BadUsbStatePaused,
BadUsbStateDone,
BadUsbStateScriptError,
BadUsbStateFileError,
} BadUsbWorkerState;
typedef struct {
BadUsbWorkerState state;
size_t line_cur;
size_t line_nb;
uint32_t delay_remain;
size_t error_line;
char error[64];
uint32_t elapsed;
} BadUsbState;
typedef struct BadUsbScript BadUsbScript;
BadUsbScript* bad_usb_script_open(
FuriString* file_path,
BadUsbHidInterface* interface,
BadUsbHidConfig* hid_cfg,
bool load_id_cfg);
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);
void bad_usb_script_start_stop(BadUsbScript* bad_usb);
void bad_usb_script_pause_resume(BadUsbScript* bad_usb);
BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb);
#ifdef __cplusplus
}
#endif

View File

@@ -3,7 +3,7 @@
#include "ducky_script.h"
#include "ducky_script_i.h"
typedef int32_t (*DuckyCmdCallback)(BadKbScript* bad_kb, const char* line, int32_t param);
typedef int32_t (*DuckyCmdCallback)(BadUsbScript* bad_usb, const char* line, int32_t param);
typedef struct {
char* name;
@@ -11,7 +11,7 @@ typedef struct {
int32_t param;
} DuckyCmd;
static int32_t ducky_fnc_delay(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_delay(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
@@ -21,54 +21,54 @@ static int32_t ducky_fnc_delay(BadKbScript* bad_kb, const char* line, int32_t pa
return (int32_t)delay_val;
}
return ducky_error(bad_kb, "Invalid number %s", line);
return ducky_error(bad_usb, "Invalid number %s", line);
}
static int32_t ducky_fnc_defdelay(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_defdelay(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
bool state = ducky_get_number(line, &bad_kb->defdelay);
bool state = ducky_get_number(line, &bad_usb->defdelay);
if(!state) {
return ducky_error(bad_kb, "Invalid number %s", line);
return ducky_error(bad_usb, "Invalid number %s", line);
}
return 0;
}
static int32_t ducky_fnc_strdelay(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_strdelay(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
bool state = ducky_get_number(line, &bad_kb->stringdelay);
bool state = ducky_get_number(line, &bad_usb->stringdelay);
if(!state) {
return ducky_error(bad_kb, "Invalid number %s", line);
return ducky_error(bad_usb, "Invalid number %s", line);
}
return 0;
}
static int32_t ducky_fnc_defstrdelay(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_defstrdelay(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
bool state = ducky_get_number(line, &bad_kb->defstringdelay);
bool state = ducky_get_number(line, &bad_usb->defstringdelay);
if(!state) {
return ducky_error(bad_kb, "Invalid number %s", line);
return ducky_error(bad_usb, "Invalid number %s", line);
}
return 0;
}
static int32_t ducky_fnc_string(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_string(BadUsbScript* bad_usb, const char* line, int32_t param) {
line = &line[ducky_get_command_len(line) + 1];
furi_string_set_str(bad_kb->string_print, line);
furi_string_set_str(bad_usb->string_print, line);
if(param == 1) {
furi_string_cat(bad_kb->string_print, "\n");
furi_string_cat(bad_usb->string_print, "\n");
}
if(bad_kb->stringdelay == 0 &&
bad_kb->defstringdelay == 0) { // stringdelay not set - run command immediately
bool state = ducky_string(bad_kb, furi_string_get_cstr(bad_kb->string_print));
if(bad_usb->stringdelay == 0 &&
bad_usb->defstringdelay == 0) { // stringdelay not set - run command immediately
bool state = ducky_string(bad_usb, furi_string_get_cstr(bad_usb->string_print));
if(!state) {
return ducky_error(bad_kb, "Invalid string %s", line);
return ducky_error(bad_usb, "Invalid string %s", line);
}
} else { // stringdelay is set - run command in thread to keep handling external events
return SCRIPT_STATE_STRING_START;
@@ -77,161 +77,161 @@ static int32_t ducky_fnc_string(BadKbScript* bad_kb, const char* line, int32_t p
return 0;
}
static int32_t ducky_fnc_repeat(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_repeat(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
bool state = ducky_get_number(line, &bad_kb->repeat_cnt);
if((!state) || (bad_kb->repeat_cnt == 0)) {
return ducky_error(bad_kb, "Invalid number %s", line);
bool state = ducky_get_number(line, &bad_usb->repeat_cnt);
if((!state) || (bad_usb->repeat_cnt == 0)) {
return ducky_error(bad_usb, "Invalid number %s", line);
}
return 0;
}
static int32_t ducky_fnc_sysrq(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_sysrq(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_keycode(bad_kb, line, true);
bad_kb->hid->kb_press(bad_kb->hid_inst, KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
bad_kb->hid->kb_press(bad_kb->hid_inst, key);
bad_kb->hid->release_all(bad_kb->hid_inst);
uint16_t key = ducky_get_keycode(bad_usb, line, true);
bad_usb->hid->kb_press(bad_usb->hid_inst, KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
bad_usb->hid->release_all(bad_usb->hid_inst);
return 0;
}
static int32_t ducky_fnc_altchar(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_altchar(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
ducky_numlock_on(bad_kb);
bool state = ducky_altchar(bad_kb, line);
ducky_numlock_on(bad_usb);
bool state = ducky_altchar(bad_usb, line);
if(!state) {
return ducky_error(bad_kb, "Invalid altchar %s", line);
return ducky_error(bad_usb, "Invalid altchar %s", line);
}
return 0;
}
static int32_t ducky_fnc_altstring(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_altstring(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
ducky_numlock_on(bad_kb);
bool state = ducky_altstring(bad_kb, line);
ducky_numlock_on(bad_usb);
bool state = ducky_altstring(bad_usb, line);
if(!state) {
return ducky_error(bad_kb, "Invalid altstring %s", line);
return ducky_error(bad_usb, "Invalid altstring %s", line);
}
return 0;
}
static int32_t ducky_fnc_hold(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_hold(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
if(bad_kb->key_hold_nb > (HID_KB_MAX_KEYS - 1)) {
return ducky_error(bad_kb, "Too many keys are held");
if(bad_usb->key_hold_nb > (HID_KB_MAX_KEYS - 1)) {
return ducky_error(bad_usb, "Too many keys are held");
}
// Handle Mouse Keys here
uint16_t key = ducky_get_mouse_keycode_by_name(line);
if(key != HID_MOUSE_NONE) {
bad_kb->key_hold_nb++;
bad_kb->hid->mouse_press(bad_kb->hid_inst, key);
bad_usb->key_hold_nb++;
bad_usb->hid->mouse_press(bad_usb->hid_inst, key);
return 0;
}
// Handle Keyboard keys here
key = ducky_get_keycode(bad_kb, line, true);
key = ducky_get_keycode(bad_usb, line, true);
if(key != HID_KEYBOARD_NONE) {
bad_kb->key_hold_nb++;
bad_kb->hid->kb_press(bad_kb->hid_inst, key);
bad_usb->key_hold_nb++;
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
return 0;
}
// keyboard and mouse were none
return ducky_error(bad_kb, "Unknown keycode for %s", line);
return ducky_error(bad_usb, "Unknown keycode for %s", line);
}
static int32_t ducky_fnc_release(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_release(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
if(bad_kb->key_hold_nb == 0) {
return ducky_error(bad_kb, "No keys are held");
if(bad_usb->key_hold_nb == 0) {
return ducky_error(bad_usb, "No keys are held");
}
// Handle Mouse Keys here
uint16_t key = ducky_get_mouse_keycode_by_name(line);
if(key != HID_MOUSE_NONE) {
bad_kb->key_hold_nb--;
bad_kb->hid->mouse_release(bad_kb->hid_inst, key);
bad_usb->key_hold_nb--;
bad_usb->hid->mouse_release(bad_usb->hid_inst, key);
return 0;
}
//Handle Keyboard Keys here
key = ducky_get_keycode(bad_kb, line, true);
key = ducky_get_keycode(bad_usb, line, true);
if(key != HID_KEYBOARD_NONE) {
bad_kb->key_hold_nb--;
bad_kb->hid->kb_release(bad_kb->hid_inst, key);
bad_usb->key_hold_nb--;
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
return 0;
}
// keyboard and mouse were none
return ducky_error(bad_kb, "No keycode defined for %s", line);
return ducky_error(bad_usb, "No keycode defined for %s", line);
}
static int32_t ducky_fnc_media(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_media(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_media_keycode_by_name(line);
if(key == HID_CONSUMER_UNASSIGNED) {
return ducky_error(bad_kb, "No keycode defined for %s", line);
return ducky_error(bad_usb, "No keycode defined for %s", line);
}
bad_kb->hid->consumer_press(bad_kb->hid_inst, key);
bad_kb->hid->consumer_release(bad_kb->hid_inst, key);
bad_usb->hid->consumer_press(bad_usb->hid_inst, key);
bad_usb->hid->consumer_release(bad_usb->hid_inst, key);
return 0;
}
static int32_t ducky_fnc_globe(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_globe(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_keycode(bad_kb, line, true);
uint16_t key = ducky_get_keycode(bad_usb, line, true);
if(key == HID_KEYBOARD_NONE) {
return ducky_error(bad_kb, "No keycode defined for %s", line);
return ducky_error(bad_usb, "No keycode defined for %s", line);
}
bad_kb->hid->consumer_press(bad_kb->hid_inst, HID_CONSUMER_FN_GLOBE);
bad_kb->hid->kb_press(bad_kb->hid_inst, key);
bad_kb->hid->kb_release(bad_kb->hid_inst, key);
bad_kb->hid->consumer_release(bad_kb->hid_inst, HID_CONSUMER_FN_GLOBE);
bad_usb->hid->consumer_press(bad_usb->hid_inst, HID_CONSUMER_FN_GLOBE);
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
bad_usb->hid->consumer_release(bad_usb->hid_inst, HID_CONSUMER_FN_GLOBE);
return 0;
}
static int32_t ducky_fnc_waitforbutton(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_waitforbutton(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
UNUSED(bad_kb);
UNUSED(bad_usb);
UNUSED(line);
return SCRIPT_STATE_WAIT_FOR_BTN;
}
static int32_t ducky_fnc_mouse_scroll(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_mouse_scroll(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[strcspn(line, " ") + 1];
int32_t mouse_scroll_dist = 0;
if(strint_to_int32(line, NULL, &mouse_scroll_dist, 10) != StrintParseNoError) {
return ducky_error(bad_kb, "Invalid Number %s", line);
return ducky_error(bad_usb, "Invalid Number %s", line);
}
bad_kb->hid->mouse_scroll(bad_kb->hid_inst, mouse_scroll_dist);
bad_usb->hid->mouse_scroll(bad_usb->hid_inst, mouse_scroll_dist);
return 0;
}
static int32_t ducky_fnc_mouse_move(BadKbScript* bad_kb, const char* line, int32_t param) {
static int32_t ducky_fnc_mouse_move(BadUsbScript* bad_usb, const char* line, int32_t param) {
UNUSED(param);
line = &line[strcspn(line, " ") + 1];
@@ -239,16 +239,16 @@ static int32_t ducky_fnc_mouse_move(BadKbScript* bad_kb, const char* line, int32
int32_t mouse_move_y = 0;
if(strint_to_int32(line, NULL, &mouse_move_x, 10) != StrintParseNoError) {
return ducky_error(bad_kb, "Invalid Number %s", line);
return ducky_error(bad_usb, "Invalid Number %s", line);
}
line = &line[strcspn(line, " ") + 1];
if(strint_to_int32(line, NULL, &mouse_move_y, 10) != StrintParseNoError) {
return ducky_error(bad_kb, "Invalid Number %s", line);
return ducky_error(bad_usb, "Invalid Number %s", line);
}
bad_kb->hid->mouse_move(bad_kb->hid_inst, mouse_move_x, mouse_move_y);
bad_usb->hid->mouse_move(bad_usb->hid_inst, mouse_move_x, mouse_move_y);
return 0;
}
@@ -283,11 +283,11 @@ static const DuckyCmd ducky_commands[] = {
{"MOUSE_SCROLL", ducky_fnc_mouse_scroll, -1},
};
#define TAG "BadKb"
#define TAG "BadUsb"
#define WORKER_TAG TAG "Worker"
int32_t ducky_execute_cmd(BadKbScript* bad_kb, const char* line) {
int32_t ducky_execute_cmd(BadUsbScript* bad_usb, const char* line) {
size_t cmd_word_len = strcspn(line, " ");
for(size_t i = 0; i < COUNT_OF(ducky_commands); i++) {
size_t cmd_compare_len = strlen(ducky_commands[i].name);
@@ -300,7 +300,7 @@ int32_t ducky_execute_cmd(BadKbScript* bad_kb, const char* line) {
if(ducky_commands[i].callback == NULL) {
return 0;
} else {
return (ducky_commands[i].callback)(bad_kb, line, ducky_commands[i].param);
return (ducky_commands[i].callback)(bad_usb, line, ducky_commands[i].param);
}
}
}

View File

@@ -7,7 +7,7 @@ extern "C" {
#include <furi.h>
#include <furi_hal.h>
#include "ducky_script.h"
#include "bad_kb_hid.h"
#include "bad_usb_hid.h"
#define SCRIPT_STATE_ERROR (-1)
#define SCRIPT_STATE_END (-2)
@@ -21,14 +21,14 @@ extern "C" {
#define HID_MOUSE_INVALID 0
#define HID_MOUSE_NONE 0
struct BadKbScript {
BadKbHidInterface* interface;
BadKbHidConfig* hid_cfg;
struct BadUsbScript {
BadUsbHidInterface* interface;
BadUsbHidConfig* hid_cfg;
bool load_id_cfg;
const BadKbHidApi* hid;
const BadUsbHidApi* hid;
void* hid_inst;
FuriThread* thread;
BadKbState st;
BadUsbState st;
FuriString* file_path;
uint8_t file_buf[FILE_BUFFER_LEN + 1];
@@ -50,7 +50,7 @@ struct BadKbScript {
size_t string_print_pos;
};
uint16_t ducky_get_keycode(BadKbScript* bad_kb, const char* param, bool accept_chars);
uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars);
uint32_t ducky_get_command_len(const char* line);
@@ -64,19 +64,19 @@ uint8_t ducky_get_mouse_keycode_by_name(const char* param);
bool ducky_get_number(const char* param, uint32_t* val);
void ducky_numlock_on(BadKbScript* bad_kb);
void ducky_numlock_on(BadUsbScript* bad_usb);
bool ducky_numpad_press(BadKbScript* bad_kb, const char num);
bool ducky_numpad_press(BadUsbScript* bad_usb, const char num);
bool ducky_altchar(BadKbScript* bad_kb, const char* charcode);
bool ducky_altchar(BadUsbScript* bad_usb, const char* charcode);
bool ducky_altstring(BadKbScript* bad_kb, const char* param);
bool ducky_altstring(BadUsbScript* bad_usb, const char* param);
bool ducky_string(BadKbScript* bad_kb, const char* param);
bool ducky_string(BadUsbScript* bad_usb, const char* param);
int32_t ducky_execute_cmd(BadKbScript* bad_kb, const char* line);
int32_t ducky_execute_cmd(BadUsbScript* bad_usb, const char* line);
int32_t ducky_error(BadKbScript* bad_kb, const char* text, ...);
int32_t ducky_error(BadUsbScript* bad_usb, const char* text, ...);
#ifdef __cplusplus
}

View File

Before

Width:  |  Height:  |  Size: 96 B

After

Width:  |  Height:  |  Size: 96 B

View File

@@ -0,0 +1,30 @@
#include "bad_usb_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const bad_usb_scene_on_enter_handlers[])(void*) = {
#include "bad_usb_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const bad_usb_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "bad_usb_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const bad_usb_scene_on_exit_handlers[])(void* context) = {
#include "bad_usb_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers bad_usb_scene_handlers = {
.on_enter_handlers = bad_usb_scene_on_enter_handlers,
.on_event_handlers = bad_usb_scene_on_event_handlers,
.on_exit_handlers = bad_usb_scene_on_exit_handlers,
.scene_num = BadUsbSceneNum,
};

View File

@@ -3,27 +3,27 @@
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) BadKbScene##id,
#define ADD_SCENE(prefix, name, id) BadUsbScene##id,
typedef enum {
#include "bad_kb_scene_config.h"
BadKbSceneNum,
} BadKbScene;
#include "bad_usb_scene_config.h"
BadUsbSceneNum,
} BadUsbScene;
#undef ADD_SCENE
extern const SceneManagerHandlers bad_kb_scene_handlers;
extern const SceneManagerHandlers bad_usb_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "bad_kb_scene_config.h"
#include "bad_usb_scene_config.h"
#undef ADD_SCENE
// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "bad_kb_scene_config.h"
#include "bad_usb_scene_config.h"
#undef ADD_SCENE
// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "bad_kb_scene_config.h"
#include "bad_usb_scene_config.h"
#undef ADD_SCENE

View File

@@ -1,4 +1,4 @@
#include "../bad_kb_app_i.h"
#include "../bad_usb_app_i.h"
enum ConfigIndex {
ConfigIndexKeyboardLayout,
@@ -21,23 +21,24 @@ enum ConfigIndexUsb {
ConfigIndexUsbRandomizeVidPid,
};
void bad_kb_scene_config_connection_callback(VariableItem* item) {
BadKbApp* bad_kb = variable_item_get_context(item);
bad_kb_set_interface(
bad_kb,
bad_kb->interface == BadKbHidInterfaceBle ? BadKbHidInterfaceUsb : BadKbHidInterfaceBle);
void bad_usb_scene_config_connection_callback(VariableItem* item) {
BadUsbApp* bad_usb = variable_item_get_context(item);
bad_usb_set_interface(
bad_usb,
bad_usb->interface == BadUsbHidInterfaceBle ? BadUsbHidInterfaceUsb :
BadUsbHidInterfaceBle);
variable_item_set_current_value_text(
item, bad_kb->interface == BadKbHidInterfaceBle ? "BLE" : "USB");
view_dispatcher_send_custom_event(bad_kb->view_dispatcher, ConfigIndexConnection);
item, bad_usb->interface == BadUsbHidInterfaceBle ? "BLE" : "USB");
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, ConfigIndexConnection);
}
void bad_kb_scene_config_ble_remember_callback(VariableItem* item) {
BadKbApp* bad_kb = variable_item_get_context(item);
void bad_usb_scene_config_ble_remember_callback(VariableItem* item) {
BadUsbApp* bad_usb = variable_item_get_context(item);
bool value = variable_item_get_current_value_index(item);
// Apply to current script config
bad_kb->script_hid_cfg.ble.bonding = value;
bad_usb->script_hid_cfg.ble.bonding = value;
// Set in user config to save in settings file
bad_kb->user_hid_cfg.ble.bonding = value;
bad_usb->user_hid_cfg.ble.bonding = value;
variable_item_set_current_value_text(item, value ? "ON" : "OFF");
}
@@ -46,24 +47,24 @@ const char* const ble_pairing_names[GapPairingCount] = {
"PIN Type",
"PIN Y/N",
};
void bad_kb_scene_config_ble_pairing_callback(VariableItem* item) {
BadKbApp* bad_kb = variable_item_get_context(item);
void bad_usb_scene_config_ble_pairing_callback(VariableItem* item) {
BadUsbApp* bad_usb = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
// Apply to current script config
bad_kb->script_hid_cfg.ble.pairing = index;
bad_usb->script_hid_cfg.ble.pairing = index;
// Set in user config to save in settings file
bad_kb->user_hid_cfg.ble.pairing = index;
bad_usb->user_hid_cfg.ble.pairing = index;
variable_item_set_current_value_text(item, ble_pairing_names[index]);
}
void bad_kb_scene_config_select_callback(void* context, uint32_t index) {
BadKbApp* bad_kb = context;
void bad_usb_scene_config_select_callback(void* context, uint32_t index) {
BadUsbApp* bad_usb = context;
view_dispatcher_send_custom_event(bad_kb->view_dispatcher, index);
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, index);
}
static void draw_menu(BadKbApp* bad_kb) {
VariableItemList* var_item_list = bad_kb->var_item_list;
static void draw_menu(BadUsbApp* bad_usb) {
VariableItemList* var_item_list = bad_usb->var_item_list;
VariableItem* item;
variable_item_list_reset(var_item_list);
@@ -71,16 +72,16 @@ static void draw_menu(BadKbApp* bad_kb) {
variable_item_list_add(var_item_list, "Keyboard Layout (global)", 0, NULL, NULL);
item = variable_item_list_add(
var_item_list, "Connection", 2, bad_kb_scene_config_connection_callback, bad_kb);
variable_item_set_current_value_index(item, bad_kb->interface == BadKbHidInterfaceBle);
var_item_list, "Connection", 2, bad_usb_scene_config_connection_callback, bad_usb);
variable_item_set_current_value_index(item, bad_usb->interface == BadUsbHidInterfaceBle);
variable_item_set_current_value_text(
item, bad_kb->interface == BadKbHidInterfaceBle ? "BLE" : "USB");
item, bad_usb->interface == BadUsbHidInterfaceBle ? "BLE" : "USB");
if(bad_kb->interface == BadKbHidInterfaceBle) {
BleProfileHidParams* ble_hid_cfg = &bad_kb->script_hid_cfg.ble;
if(bad_usb->interface == BadUsbHidInterfaceBle) {
BleProfileHidParams* ble_hid_cfg = &bad_usb->script_hid_cfg.ble;
item = variable_item_list_add(
var_item_list, "BLE Remember", 2, bad_kb_scene_config_ble_remember_callback, bad_kb);
var_item_list, "BLE Remember", 2, bad_usb_scene_config_ble_remember_callback, bad_usb);
variable_item_set_current_value_index(item, ble_hid_cfg->bonding);
variable_item_set_current_value_text(item, ble_hid_cfg->bonding ? "ON" : "OFF");
@@ -88,8 +89,8 @@ static void draw_menu(BadKbApp* bad_kb) {
var_item_list,
"BLE Pairing",
GapPairingCount,
bad_kb_scene_config_ble_pairing_callback,
bad_kb);
bad_usb_scene_config_ble_pairing_callback,
bad_usb);
variable_item_set_current_value_index(item, ble_hid_cfg->pairing);
variable_item_set_current_value_text(item, ble_pairing_names[ble_hid_cfg->pairing]);
@@ -111,60 +112,60 @@ static void draw_menu(BadKbApp* bad_kb) {
}
}
void bad_kb_scene_config_on_enter(void* context) {
BadKbApp* bad_kb = context;
VariableItemList* var_item_list = bad_kb->var_item_list;
void bad_usb_scene_config_on_enter(void* context) {
BadUsbApp* bad_usb = context;
VariableItemList* var_item_list = bad_usb->var_item_list;
variable_item_list_set_enter_callback(
var_item_list, bad_kb_scene_config_select_callback, bad_kb);
draw_menu(bad_kb);
var_item_list, bad_usb_scene_config_select_callback, bad_usb);
draw_menu(bad_usb);
variable_item_list_set_selected_item(
var_item_list, scene_manager_get_scene_state(bad_kb->scene_manager, BadKbSceneConfig));
var_item_list, scene_manager_get_scene_state(bad_usb->scene_manager, BadUsbSceneConfig));
view_dispatcher_switch_to_view(bad_kb->view_dispatcher, BadKbAppViewConfig);
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewConfig);
}
bool bad_kb_scene_config_on_event(void* context, SceneManagerEvent event) {
BadKbApp* bad_kb = context;
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_kb->scene_manager, BadKbSceneConfig, event.event);
scene_manager_set_scene_state(bad_usb->scene_manager, BadUsbSceneConfig, event.event);
consumed = true;
switch(event.event) {
case ConfigIndexKeyboardLayout:
scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigLayout);
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigLayout);
break;
case ConfigIndexConnection:
// Refresh default values for new interface
const BadKbHidApi* hid = bad_kb_hid_get_interface(bad_kb->interface);
hid->adjust_config(&bad_kb->script_hid_cfg);
const BadUsbHidApi* hid = bad_usb_hid_get_interface(bad_usb->interface);
hid->adjust_config(&bad_usb->script_hid_cfg);
// Redraw menu with new interface options
draw_menu(bad_kb);
draw_menu(bad_usb);
break;
default:
break;
}
if(bad_kb->interface == BadKbHidInterfaceBle) {
if(bad_usb->interface == BadUsbHidInterfaceBle) {
switch(event.event) {
case ConfigIndexBleDeviceName:
scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigBleName);
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigBleName);
break;
case ConfigIndexBleMacAddress:
scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigBleMac);
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigBleMac);
break;
case ConfigIndexBleRandomizeMac:
// Apply to current script config
furi_hal_random_fill_buf(
bad_kb->script_hid_cfg.ble.mac, sizeof(bad_kb->script_hid_cfg.ble.mac));
bad_usb->script_hid_cfg.ble.mac, sizeof(bad_usb->script_hid_cfg.ble.mac));
// Set in user config to save in settings file
memcpy(
bad_kb->user_hid_cfg.ble.mac,
bad_kb->script_hid_cfg.ble.mac,
sizeof(bad_kb->user_hid_cfg.ble.mac));
bad_usb->user_hid_cfg.ble.mac,
bad_usb->script_hid_cfg.ble.mac,
sizeof(bad_usb->user_hid_cfg.ble.mac));
break;
case ConfigIndexBleUnpair:
scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfirmUnpair);
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfirmUnpair);
break;
default:
break;
@@ -173,26 +174,26 @@ bool bad_kb_scene_config_on_event(void* context, SceneManagerEvent event) {
switch(event.event) {
case ConfigIndexUsbManufacturer:
scene_manager_set_scene_state(
bad_kb->scene_manager, BadKbSceneConfigUsbName, true);
scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigUsbName);
bad_usb->scene_manager, BadUsbSceneConfigUsbName, true);
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigUsbName);
break;
case ConfigIndexUsbProductName:
scene_manager_set_scene_state(
bad_kb->scene_manager, BadKbSceneConfigUsbName, false);
scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigUsbName);
bad_usb->scene_manager, BadUsbSceneConfigUsbName, false);
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigUsbName);
break;
case ConfigIndexUsbVidPid:
scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneConfigUsbVidPid);
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigUsbVidPid);
break;
case ConfigIndexUsbRandomizeVidPid:
furi_hal_random_fill_buf(
(void*)bad_kb->usb_vidpid_buf, sizeof(bad_kb->usb_vidpid_buf));
(void*)bad_usb->usb_vidpid_buf, sizeof(bad_usb->usb_vidpid_buf));
// Apply to current script config
bad_kb->script_hid_cfg.usb.vid = bad_kb->usb_vidpid_buf[0];
bad_kb->script_hid_cfg.usb.pid = bad_kb->usb_vidpid_buf[1];
bad_usb->script_hid_cfg.usb.vid = bad_usb->usb_vidpid_buf[0];
bad_usb->script_hid_cfg.usb.pid = bad_usb->usb_vidpid_buf[1];
// Set in user config to save in settings file
bad_kb->user_hid_cfg.usb.vid = bad_kb->script_hid_cfg.usb.vid;
bad_kb->user_hid_cfg.usb.pid = bad_kb->script_hid_cfg.usb.pid;
bad_usb->user_hid_cfg.usb.vid = bad_usb->script_hid_cfg.usb.vid;
bad_usb->user_hid_cfg.usb.pid = bad_usb->script_hid_cfg.usb.pid;
break;
default:
break;
@@ -203,9 +204,9 @@ bool bad_kb_scene_config_on_event(void* context, SceneManagerEvent event) {
return consumed;
}
void bad_kb_scene_config_on_exit(void* context) {
BadKbApp* bad_kb = context;
VariableItemList* var_item_list = bad_kb->var_item_list;
void bad_usb_scene_config_on_exit(void* context) {
BadUsbApp* bad_usb = context;
VariableItemList* var_item_list = bad_usb->var_item_list;
variable_item_list_reset(var_item_list);
}

View File

@@ -0,0 +1,11 @@
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)
ADD_SCENE(bad_usb, config_ble_name, ConfigBleName)
ADD_SCENE(bad_usb, config_ble_mac, ConfigBleMac)
ADD_SCENE(bad_usb, config_usb_name, ConfigUsbName)
ADD_SCENE(bad_usb, config_usb_vidpid, ConfigUsbVidPid)
ADD_SCENE(bad_usb, confirm_unpair, ConfirmUnpair)
ADD_SCENE(bad_usb, unpair_done, UnpairDone)

View File

@@ -0,0 +1,71 @@
#include "../bad_usb_app_i.h"
enum ByteInputResult {
ByteInputResultOk,
};
static void reverse_mac_addr(uint8_t mac_addr[GAP_MAC_ADDR_SIZE]) {
uint8_t tmp;
for(size_t i = 0; i < GAP_MAC_ADDR_SIZE / 2; i++) {
tmp = mac_addr[i];
mac_addr[i] = mac_addr[GAP_MAC_ADDR_SIZE - 1 - i];
mac_addr[GAP_MAC_ADDR_SIZE - 1 - i] = tmp;
}
}
void bad_usb_scene_config_ble_mac_byte_input_callback(void* context) {
BadUsbApp* bad_usb = context;
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, ByteInputResultOk);
}
void bad_usb_scene_config_ble_mac_on_enter(void* context) {
BadUsbApp* bad_usb = context;
ByteInput* byte_input = bad_usb->byte_input;
memcpy(bad_usb->ble_mac_buf, bad_usb->script_hid_cfg.ble.mac, sizeof(bad_usb->ble_mac_buf));
reverse_mac_addr(bad_usb->ble_mac_buf);
byte_input_set_header_text(byte_input, "Set BLE MAC address");
byte_input_set_result_callback(
byte_input,
bad_usb_scene_config_ble_mac_byte_input_callback,
NULL,
bad_usb,
bad_usb->ble_mac_buf,
sizeof(bad_usb->ble_mac_buf));
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewByteInput);
}
bool bad_usb_scene_config_ble_mac_on_event(void* context, SceneManagerEvent event) {
BadUsbApp* bad_usb = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == ByteInputResultOk) {
reverse_mac_addr(bad_usb->ble_mac_buf);
// Apply to current script config
memcpy(
bad_usb->script_hid_cfg.ble.mac,
bad_usb->ble_mac_buf,
sizeof(bad_usb->script_hid_cfg.ble.mac));
// Set in user config to save in settings file
memcpy(
bad_usb->user_hid_cfg.ble.mac,
bad_usb->ble_mac_buf,
sizeof(bad_usb->user_hid_cfg.ble.mac));
}
scene_manager_previous_scene(bad_usb->scene_manager);
}
return consumed;
}
void bad_usb_scene_config_ble_mac_on_exit(void* context) {
BadUsbApp* bad_usb = context;
ByteInput* byte_input = bad_usb->byte_input;
byte_input_set_result_callback(byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(byte_input, "");
}

View File

@@ -0,0 +1,60 @@
#include "../bad_usb_app_i.h"
enum TextInputResult {
TextInputResultOk,
};
static void bad_usb_scene_config_ble_name_text_input_callback(void* context) {
BadUsbApp* bad_usb = context;
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, TextInputResultOk);
}
void bad_usb_scene_config_ble_name_on_enter(void* context) {
BadUsbApp* bad_usb = context;
TextInput* text_input = bad_usb->text_input;
strlcpy(
bad_usb->ble_name_buf, bad_usb->script_hid_cfg.ble.name, sizeof(bad_usb->ble_name_buf));
text_input_set_header_text(text_input, "Set BLE device name");
text_input_set_result_callback(
text_input,
bad_usb_scene_config_ble_name_text_input_callback,
bad_usb,
bad_usb->ble_name_buf,
sizeof(bad_usb->ble_name_buf),
true);
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewTextInput);
}
bool bad_usb_scene_config_ble_name_on_event(void* context, SceneManagerEvent event) {
BadUsbApp* bad_usb = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == TextInputResultOk) {
// Apply to current script config
strlcpy(
bad_usb->script_hid_cfg.ble.name,
bad_usb->ble_name_buf,
sizeof(bad_usb->script_hid_cfg.ble.name));
// Set in user config to save in settings file
strlcpy(
bad_usb->user_hid_cfg.ble.name,
bad_usb->ble_name_buf,
sizeof(bad_usb->user_hid_cfg.ble.name));
}
scene_manager_previous_scene(bad_usb->scene_manager);
}
return consumed;
}
void bad_usb_scene_config_ble_name_on_exit(void* context) {
BadUsbApp* bad_usb = context;
TextInput* text_input = bad_usb->text_input;
text_input_reset(text_input);
}

View File

@@ -0,0 +1,45 @@
#include "../bad_usb_app_i.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;
bad_usb_layout_select(bad_usb);
scene_manager_previous_scene(bad_usb->scene_manager);
}
bool bad_usb_scene_config_layout_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void bad_usb_scene_config_layout_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -0,0 +1,83 @@
#include "../bad_usb_app_i.h"
enum TextInputResult {
TextInputResultOk,
};
static void bad_usb_scene_config_usb_name_text_input_callback(void* context) {
BadUsbApp* bad_usb = context;
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, TextInputResultOk);
}
void bad_usb_scene_config_usb_name_on_enter(void* context) {
BadUsbApp* bad_usb = context;
TextInput* text_input = bad_usb->text_input;
if(scene_manager_get_scene_state(bad_usb->scene_manager, BadUsbSceneConfigUsbName)) {
strlcpy(
bad_usb->usb_name_buf,
bad_usb->script_hid_cfg.usb.manuf,
sizeof(bad_usb->usb_name_buf));
text_input_set_header_text(text_input, "Set USB manufacturer name");
} else {
strlcpy(
bad_usb->usb_name_buf,
bad_usb->script_hid_cfg.usb.product,
sizeof(bad_usb->usb_name_buf));
text_input_set_header_text(text_input, "Set USB product name");
}
text_input_set_result_callback(
text_input,
bad_usb_scene_config_usb_name_text_input_callback,
bad_usb,
bad_usb->usb_name_buf,
sizeof(bad_usb->usb_name_buf),
true);
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewTextInput);
}
bool bad_usb_scene_config_usb_name_on_event(void* context, SceneManagerEvent event) {
BadUsbApp* bad_usb = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == TextInputResultOk) {
if(scene_manager_get_scene_state(bad_usb->scene_manager, BadUsbSceneConfigUsbName)) {
// Apply to current script config
strlcpy(
bad_usb->script_hid_cfg.usb.manuf,
bad_usb->usb_name_buf,
sizeof(bad_usb->script_hid_cfg.usb.manuf));
// Set in user config to save in settings file
strlcpy(
bad_usb->user_hid_cfg.usb.manuf,
bad_usb->usb_name_buf,
sizeof(bad_usb->user_hid_cfg.usb.manuf));
} else {
// Apply to current script config
strlcpy(
bad_usb->script_hid_cfg.usb.product,
bad_usb->usb_name_buf,
sizeof(bad_usb->script_hid_cfg.usb.product));
// Set in user config to save in settings file
strlcpy(
bad_usb->user_hid_cfg.usb.product,
bad_usb->usb_name_buf,
sizeof(bad_usb->user_hid_cfg.usb.product));
}
}
scene_manager_previous_scene(bad_usb->scene_manager);
}
return consumed;
}
void bad_usb_scene_config_usb_name_on_exit(void* context) {
BadUsbApp* bad_usb = context;
TextInput* text_input = bad_usb->text_input;
text_input_reset(text_input);
}

View File

@@ -0,0 +1,57 @@
#include "../bad_usb_app_i.h"
enum ByteInputResult {
ByteInputResultOk,
};
void bad_usb_scene_config_usb_vidpid_byte_input_callback(void* context) {
BadUsbApp* bad_usb = context;
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, ByteInputResultOk);
}
void bad_usb_scene_config_usb_vidpid_on_enter(void* context) {
BadUsbApp* bad_usb = context;
ByteInput* byte_input = bad_usb->byte_input;
bad_usb->usb_vidpid_buf[0] = __REVSH(bad_usb->script_hid_cfg.usb.vid);
bad_usb->usb_vidpid_buf[1] = __REVSH(bad_usb->script_hid_cfg.usb.pid);
byte_input_set_header_text(byte_input, "Set USB VID:PID");
byte_input_set_result_callback(
byte_input,
bad_usb_scene_config_usb_vidpid_byte_input_callback,
NULL,
bad_usb,
(void*)bad_usb->usb_vidpid_buf,
sizeof(bad_usb->usb_vidpid_buf));
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewByteInput);
}
bool bad_usb_scene_config_usb_vidpid_on_event(void* context, SceneManagerEvent event) {
BadUsbApp* bad_usb = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == ByteInputResultOk) {
// Apply to current script config
bad_usb->script_hid_cfg.usb.vid = __REVSH(bad_usb->usb_vidpid_buf[0]);
bad_usb->script_hid_cfg.usb.pid = __REVSH(bad_usb->usb_vidpid_buf[1]);
// Set in user config to save in settings file
bad_usb->user_hid_cfg.usb.vid = bad_usb->script_hid_cfg.usb.vid;
bad_usb->user_hid_cfg.usb.pid = bad_usb->script_hid_cfg.usb.pid;
}
scene_manager_previous_scene(bad_usb->scene_manager);
}
return consumed;
}
void bad_usb_scene_config_usb_vidpid_on_exit(void* context) {
BadUsbApp* bad_usb = context;
ByteInput* byte_input = bad_usb->byte_input;
byte_input_set_result_callback(byte_input, NULL, NULL, NULL, NULL, 0);
byte_input_set_header_text(byte_input, "");
}

View File

@@ -0,0 +1,53 @@
#include "../bad_usb_app_i.h"
void bad_usb_scene_confirm_unpair_widget_callback(
GuiButtonType type,
InputType input_type,
void* context) {
UNUSED(input_type);
SceneManagerEvent event = {.type = SceneManagerEventTypeCustom, .event = type};
bad_usb_scene_confirm_unpair_on_event(context, event);
}
void bad_usb_scene_confirm_unpair_on_enter(void* context) {
BadUsbApp* bad_usb = context;
Widget* widget = bad_usb->widget;
widget_add_button_element(
widget, GuiButtonTypeLeft, "Cancel", bad_usb_scene_confirm_unpair_widget_callback, context);
widget_add_button_element(
widget,
GuiButtonTypeRight,
"Unpair",
bad_usb_scene_confirm_unpair_widget_callback,
context);
widget_add_text_box_element(
widget, 0, 0, 128, 64, AlignCenter, AlignTop, "\e#Unpair the Device?\e#\n", false);
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewWidget);
}
bool bad_usb_scene_confirm_unpair_on_event(void* context, SceneManagerEvent event) {
BadUsbApp* bad_usb = context;
SceneManager* scene_manager = bad_usb->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == GuiButtonTypeRight) {
scene_manager_next_scene(scene_manager, BadUsbSceneUnpairDone);
} else if(event.event == GuiButtonTypeLeft) {
scene_manager_previous_scene(scene_manager);
}
}
return consumed;
}
void bad_usb_scene_confirm_unpair_on_exit(void* context) {
BadUsbApp* bad_usb = context;
Widget* widget = bad_usb->widget;
widget_reset(widget);
}

View File

@@ -1,23 +1,23 @@
#include "../bad_kb_app_i.h"
#include "../bad_usb_app_i.h"
typedef enum {
BadKbCustomEventErrorBack,
} BadKbCustomEvent;
BadUsbCustomEventErrorBack,
} BadUsbCustomEvent;
static void
bad_kb_scene_error_event_callback(GuiButtonType result, InputType type, void* context) {
bad_usb_scene_error_event_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context);
BadKbApp* app = context;
BadUsbApp* app = context;
if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
view_dispatcher_send_custom_event(app->view_dispatcher, BadKbCustomEventErrorBack);
view_dispatcher_send_custom_event(app->view_dispatcher, BadUsbCustomEventErrorBack);
}
}
void bad_kb_scene_error_on_enter(void* context) {
BadKbApp* app = context;
void bad_usb_scene_error_on_enter(void* context) {
BadUsbApp* app = context;
if(app->error == BadKbAppErrorNoFiles) {
if(app->error == BadUsbAppErrorNoFiles) {
widget_add_icon_element(app->widget, 0, 0, &I_SDQuestion_35x43);
widget_add_string_multiline_element(
app->widget,
@@ -28,18 +28,18 @@ void bad_kb_scene_error_on_enter(void* context) {
FontSecondary,
"No SD card or\napp data found.\nThis app will not\nwork without\nrequired files.");
widget_add_button_element(
app->widget, GuiButtonTypeLeft, "Back", bad_kb_scene_error_event_callback, app);
app->widget, GuiButtonTypeLeft, "Back", bad_usb_scene_error_event_callback, app);
}
view_dispatcher_switch_to_view(app->view_dispatcher, BadKbAppViewWidget);
view_dispatcher_switch_to_view(app->view_dispatcher, BadUsbAppViewWidget);
}
bool bad_kb_scene_error_on_event(void* context, SceneManagerEvent event) {
BadKbApp* app = context;
bool bad_usb_scene_error_on_event(void* context, SceneManagerEvent event) {
BadUsbApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == BadKbCustomEventErrorBack) {
if(event.event == BadUsbCustomEventErrorBack) {
view_dispatcher_stop(app->view_dispatcher);
consumed = true;
}
@@ -47,7 +47,7 @@ bool bad_kb_scene_error_on_event(void* context, SceneManagerEvent event) {
return consumed;
}
void bad_kb_scene_error_on_exit(void* context) {
BadKbApp* app = context;
void bad_usb_scene_error_on_exit(void* context) {
BadUsbApp* app = context;
widget_reset(app->widget);
}

View File

@@ -1,10 +1,10 @@
#include "../bad_kb_app_i.h"
#include "../bad_usb_app_i.h"
#include <storage/storage.h>
static bool bad_kb_file_select(BadKbApp* bad_kb) {
furi_assert(bad_kb);
static bool bad_usb_file_select(BadUsbApp* bad_usb) {
furi_assert(bad_usb);
bad_kb_app_show_loading_popup(bad_kb, true);
bad_usb_app_show_loading_popup(bad_usb, true);
Storage* storage = furi_record_open(RECORD_STORAGE);
if(storage_dir_exists(storage, EXT_PATH("badkb"))) {
DialogMessage* message = dialog_message_alloc();
@@ -24,48 +24,48 @@ static bool bad_kb_file_select(BadKbApp* bad_kb) {
dialog_message_free(message);
furi_record_close(RECORD_DIALOGS);
if(res == DialogMessageButtonRight) {
storage_common_migrate(storage, EXT_PATH("badkb"), BAD_KB_APP_BASE_FOLDER);
storage_common_migrate(storage, EXT_PATH("badkb"), BAD_USB_APP_BASE_FOLDER);
}
}
storage_simply_mkdir(storage, BAD_KB_APP_BASE_FOLDER);
storage_simply_mkdir(storage, BAD_USB_APP_BASE_FOLDER);
furi_record_close(RECORD_STORAGE);
bad_kb_app_show_loading_popup(bad_kb, false);
bad_usb_app_show_loading_popup(bad_usb, false);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(
&browser_options, BAD_KB_APP_SCRIPT_EXTENSION, &I_badkb_10px);
browser_options.base_path = BAD_KB_APP_BASE_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
bool res = dialog_file_browser_show(
bad_kb->dialogs, bad_kb->file_path, bad_kb->file_path, &browser_options);
bad_usb->dialogs, bad_usb->file_path, bad_usb->file_path, &browser_options);
return res;
}
void bad_kb_scene_file_select_on_enter(void* context) {
BadKbApp* bad_kb = context;
void bad_usb_scene_file_select_on_enter(void* context) {
BadUsbApp* bad_usb = context;
if(bad_kb->bad_kb_script) {
bad_kb_script_close(bad_kb->bad_kb_script);
bad_kb->bad_kb_script = NULL;
if(bad_usb->bad_usb_script) {
bad_usb_script_close(bad_usb->bad_usb_script);
bad_usb->bad_usb_script = NULL;
}
if(bad_kb_file_select(bad_kb)) {
scene_manager_set_scene_state(bad_kb->scene_manager, BadKbSceneWork, true);
scene_manager_next_scene(bad_kb->scene_manager, BadKbSceneWork);
if(bad_usb_file_select(bad_usb)) {
scene_manager_set_scene_state(bad_usb->scene_manager, BadUsbSceneWork, true);
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneWork);
} else {
view_dispatcher_stop(bad_kb->view_dispatcher);
view_dispatcher_stop(bad_usb->view_dispatcher);
}
}
bool bad_kb_scene_file_select_on_event(void* context, SceneManagerEvent event) {
bool bad_usb_scene_file_select_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void bad_kb_scene_file_select_on_exit(void* context) {
void bad_usb_scene_file_select_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -0,0 +1,39 @@
#include "../bad_usb_app_i.h"
static void bad_usb_scene_unpair_done_popup_callback(void* context) {
BadUsbApp* bad_usb = context;
scene_manager_search_and_switch_to_previous_scene(bad_usb->scene_manager, BadUsbSceneConfig);
}
void bad_usb_scene_unpair_done_on_enter(void* context) {
BadUsbApp* bad_usb = context;
Popup* popup = bad_usb->popup;
bad_usb_hid_ble_remove_pairing();
popup_set_icon(popup, 48, 4, &I_DolphinDone_80x58);
popup_set_header(popup, "Done", 20, 19, AlignLeft, AlignBottom);
popup_set_callback(popup, bad_usb_scene_unpair_done_popup_callback);
popup_set_context(popup, bad_usb);
popup_set_timeout(popup, 1500);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewPopup);
}
bool bad_usb_scene_unpair_done_on_event(void* context, SceneManagerEvent event) {
BadUsbApp* bad_usb = context;
UNUSED(bad_usb);
UNUSED(event);
bool consumed = false;
return consumed;
}
void bad_usb_scene_unpair_done_on_exit(void* context) {
BadUsbApp* bad_usb = context;
Popup* popup = bad_usb->popup;
UNUSED(popup);
popup_reset(popup);
}

View File

@@ -0,0 +1,90 @@
#include "../helpers/ducky_script.h"
#include "../bad_usb_app_i.h"
#include "../views/bad_usb_view.h"
#include <furi_hal.h>
#include "toolbox/path.h"
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, key);
}
bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
BadUsbApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == InputKeyLeft) {
if(bad_usb_view_is_idle_state(app->bad_usb_view)) {
bad_usb_script_close(app->bad_usb_script);
app->bad_usb_script = NULL;
scene_manager_next_scene(app->scene_manager, BadUsbSceneConfig);
}
consumed = true;
} else if(event.event == InputKeyOk) {
bad_usb_script_start_stop(app->bad_usb_script);
consumed = true;
} else if(event.event == InputKeyRight) {
if(bad_usb_view_is_idle_state(app->bad_usb_view)) {
bad_usb_set_interface(
app,
app->interface == BadUsbHidInterfaceBle ? BadUsbHidInterfaceUsb :
BadUsbHidInterfaceBle);
bad_usb_script_close(app->bad_usb_script);
app->bad_usb_script = bad_usb_script_open(
app->file_path, &app->interface, &app->script_hid_cfg, false);
bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout);
} else {
bad_usb_script_pause_resume(app->bad_usb_script);
}
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
bad_usb_view_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script));
bad_usb_view_set_interface(app->bad_usb_view, app->interface);
}
return consumed;
}
void bad_usb_scene_work_on_enter(void* context) {
BadUsbApp* app = context;
bad_usb_view_set_interface(app->bad_usb_view, app->interface);
// Opening script the first time:
// - copy user settings as base config
// - load ID/BLE_ID/BT_ID config if present
// Then disable this until next script selected so user can customize options
bool first_script_load = scene_manager_get_scene_state(app->scene_manager, BadUsbSceneWork);
if(first_script_load) {
memcpy(&app->script_hid_cfg, &app->user_hid_cfg, sizeof(app->script_hid_cfg));
scene_manager_set_scene_state(app->scene_manager, BadUsbSceneWork, false);
}
// Interface and config are passed as pointers as ID/BLE_ID/BT_ID config can modify them
app->bad_usb_script = bad_usb_script_open(
app->file_path, &app->interface, &app->script_hid_cfg, first_script_load);
bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout);
FuriString* file_name;
file_name = furi_string_alloc();
path_extract_filename(app->file_path, file_name, true);
bad_usb_view_set_file_name(app->bad_usb_view, furi_string_get_cstr(file_name));
furi_string_free(file_name);
FuriString* layout;
layout = furi_string_alloc();
path_extract_filename(app->keyboard_layout, layout, true);
bad_usb_view_set_layout(app->bad_usb_view, furi_string_get_cstr(layout));
furi_string_free(layout);
bad_usb_view_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script));
bad_usb_view_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) {
UNUSED(context);
}

View File

@@ -1,4 +1,4 @@
#include "bad_kb_view.h"
#include "bad_usb_view.h"
#include "../helpers/ducky_script.h"
#include <toolbox/path.h>
#include <gui/elements.h>
@@ -7,24 +7,24 @@
#define MAX_NAME_LEN 64
struct BadKb {
struct BadUsb {
View* view;
BadKbButtonCallback callback;
BadUsbButtonCallback callback;
void* context;
};
typedef struct {
char file_name[MAX_NAME_LEN];
char layout[MAX_NAME_LEN];
BadKbState state;
BadUsbState state;
bool pause_wait;
uint8_t anim_frame;
BadKbHidInterface interface;
BadUsbHidInterface interface;
Bt* bt;
} BadKbModel;
} BadUsbModel;
static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
BadKbModel* model = _model;
static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
BadUsbModel* model = _model;
FuriString* disp_str = furi_string_alloc_set(model->file_name);
elements_string_fit_width(canvas, disp_str, 128 - 2);
@@ -36,7 +36,7 @@ static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
} else {
furi_string_printf(disp_str, "(%s)", model->layout);
}
if(model->interface == BadKbHidInterfaceBle && model->bt->pin_code) {
if(model->interface == BadUsbHidInterfaceBle && model->bt->pin_code) {
furi_string_cat_printf(disp_str, " PIN: %ld", model->bt->pin_code);
} else {
uint32_t e = model->state.elapsed;
@@ -48,49 +48,49 @@ static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
furi_string_reset(disp_str);
if(model->interface == BadKbHidInterfaceBle) {
if(model->interface == BadUsbHidInterfaceBle) {
canvas_draw_icon(canvas, 22, 24, &I_Bad_BLE_48x22);
} else {
canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22);
}
BadKbWorkerState state = model->state.state;
BadUsbWorkerState state = model->state.state;
if((state == BadKbStateIdle) || (state == BadKbStateDone) ||
(state == BadKbStateNotConnected)) {
if((state == BadUsbStateIdle) || (state == BadUsbStateDone) ||
(state == BadUsbStateNotConnected)) {
elements_button_center(canvas, "Run");
elements_button_left(canvas, "Config");
elements_button_right(canvas, model->interface == BadKbHidInterfaceBle ? "USB" : "BLE");
} else if((state == BadKbStateRunning) || (state == BadKbStateDelay)) {
elements_button_right(canvas, model->interface == BadUsbHidInterfaceBle ? "USB" : "BLE");
} else if((state == BadUsbStateRunning) || (state == BadUsbStateDelay)) {
elements_button_center(canvas, "Stop");
if(!model->pause_wait) {
elements_button_right(canvas, "Pause");
}
} else if(state == BadKbStatePaused) {
} else if(state == BadUsbStatePaused) {
elements_button_center(canvas, "End");
elements_button_right(canvas, "Resume");
} else if(state == BadKbStateWaitForBtn) {
} else if(state == BadUsbStateWaitForBtn) {
elements_button_center(canvas, "Press to continue");
} else if(state == BadKbStateWillRun) {
} else if(state == BadUsbStateWillRun) {
elements_button_center(canvas, "Cancel");
}
if(state == BadKbStateNotConnected) {
if(state == BadUsbStateNotConnected) {
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Connect");
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "to device");
} else if(state == BadKbStateWillRun) {
} else if(state == BadUsbStateWillRun) {
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will run");
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "on connect");
} else if(state == BadKbStateFileError) {
} else if(state == BadUsbStateFileError) {
canvas_draw_icon(canvas, 4, 26, &I_Error_18x18);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "File");
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "ERROR");
} else if(state == BadKbStateScriptError) {
} else if(state == BadUsbStateScriptError) {
canvas_draw_icon(canvas, 4, 26, &I_Error_18x18);
furi_string_printf(disp_str, "line %zu", model->state.error_line);
canvas_draw_str_aligned(
@@ -101,7 +101,7 @@ static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
canvas, 127, 56, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:");
} else if(state == BadKbStateIdle) {
} else if(state == BadUsbStateIdle) {
canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18);
furi_string_printf(disp_str, "0/%zu", model->state.line_nb);
canvas_draw_str_aligned(
@@ -109,7 +109,7 @@ static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
canvas_set_font(canvas, FontBigNumbers);
canvas_draw_str_aligned(canvas, 112, 37, AlignRight, AlignBottom, "0");
canvas_draw_icon(canvas, 115, 23, &I_Percent_10x14);
} else if(state == BadKbStateRunning) {
} else if(state == BadUsbStateRunning) {
if(model->anim_frame == 0) {
canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21);
} else {
@@ -124,7 +124,7 @@ static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
canvas_draw_str_aligned(
canvas, 112, 37, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
canvas_draw_icon(canvas, 115, 23, &I_Percent_10x14);
} else if(state == BadKbStateDone) {
} else if(state == BadUsbStateDone) {
canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21);
furi_string_printf(disp_str, "%zu/%zu", model->state.line_nb, model->state.line_nb);
canvas_draw_str_aligned(
@@ -132,7 +132,7 @@ static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
canvas_set_font(canvas, FontBigNumbers);
canvas_draw_str_aligned(canvas, 112, 37, AlignRight, AlignBottom, "100");
canvas_draw_icon(canvas, 115, 23, &I_Percent_10x14);
} else if(state == BadKbStateDelay) {
} else if(state == BadUsbStateDelay) {
if(model->anim_frame == 0) {
canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21);
} else {
@@ -153,13 +153,13 @@ static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
canvas_draw_str_aligned(
canvas, 112, 37, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
canvas_draw_icon(canvas, 115, 23, &I_Percent_10x14);
} else if((state == BadKbStatePaused) || (state == BadKbStateWaitForBtn)) {
} else if((state == BadUsbStatePaused) || (state == BadUsbStateWaitForBtn)) {
if(model->anim_frame == 0) {
canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21);
} else {
canvas_draw_icon(canvas, 4, 23, &I_EviWaiting2_18x21);
}
if(state != BadKbStateWaitForBtn) {
if(state != BadUsbStateWaitForBtn) {
canvas_draw_str_aligned(canvas, 4, 61, AlignLeft, AlignBottom, "Paused");
}
furi_string_printf(disp_str, "%zu/%zu", model->state.line_cur, model->state.line_nb);
@@ -178,122 +178,132 @@ static void bad_kb_draw_callback(Canvas* canvas, void* _model) {
furi_string_free(disp_str);
}
static bool bad_kb_input_callback(InputEvent* event, void* context) {
static bool bad_usb_input_callback(InputEvent* event, void* context) {
furi_assert(context);
BadKb* bad_kb = context;
BadUsb* bad_usb = context;
bool consumed = false;
if(event->type == InputTypeShort) {
if(event->key == InputKeyLeft) {
consumed = true;
furi_assert(bad_kb->callback);
bad_kb->callback(event->key, bad_kb->context);
furi_assert(bad_usb->callback);
bad_usb->callback(event->key, bad_usb->context);
} else if(event->key == InputKeyOk) {
with_view_model(
bad_kb->view, BadKbModel * model, { model->pause_wait = false; }, true);
bad_usb->view, BadUsbModel * model, { model->pause_wait = false; }, true);
consumed = true;
furi_assert(bad_kb->callback);
bad_kb->callback(event->key, bad_kb->context);
furi_assert(bad_usb->callback);
bad_usb->callback(event->key, bad_usb->context);
} else if(event->key == InputKeyRight) {
with_view_model(
bad_kb->view,
BadKbModel * model,
bad_usb->view,
BadUsbModel * model,
{
if((model->state.state == BadKbStateRunning) ||
(model->state.state == BadKbStateDelay)) {
if((model->state.state == BadUsbStateRunning) ||
(model->state.state == BadUsbStateDelay)) {
model->pause_wait = true;
}
},
true);
consumed = true;
furi_assert(bad_kb->callback);
bad_kb->callback(event->key, bad_kb->context);
furi_assert(bad_usb->callback);
bad_usb->callback(event->key, bad_usb->context);
}
}
return consumed;
}
BadKb* bad_kb_view_alloc(void) {
BadKb* bad_kb = malloc(sizeof(BadKb));
BadUsb* bad_usb_view_alloc(void) {
BadUsb* bad_usb = malloc(sizeof(BadUsb));
bad_kb->view = view_alloc();
view_allocate_model(bad_kb->view, ViewModelTypeLocking, sizeof(BadKbModel));
view_set_context(bad_kb->view, bad_kb);
view_set_draw_callback(bad_kb->view, bad_kb_draw_callback);
view_set_input_callback(bad_kb->view, bad_kb_input_callback);
bad_usb->view = view_alloc();
view_allocate_model(bad_usb->view, ViewModelTypeLocking, sizeof(BadUsbModel));
view_set_context(bad_usb->view, bad_usb);
view_set_draw_callback(bad_usb->view, bad_usb_draw_callback);
view_set_input_callback(bad_usb->view, bad_usb_input_callback);
with_view_model(
bad_kb->view, BadKbModel * model, { model->bt = furi_record_open(RECORD_BT); }, true);
bad_usb->view, BadUsbModel * model, { model->bt = furi_record_open(RECORD_BT); }, true);
return bad_kb;
return bad_usb;
}
void bad_kb_view_free(BadKb* bad_kb) {
furi_assert(bad_kb);
void bad_usb_view_free(BadUsb* bad_usb) {
furi_assert(bad_usb);
furi_record_close(RECORD_BT);
view_free(bad_kb->view);
free(bad_kb);
view_free(bad_usb->view);
free(bad_usb);
}
View* bad_kb_view_get_view(BadKb* bad_kb) {
furi_assert(bad_kb);
return bad_kb->view;
View* bad_usb_view_get_view(BadUsb* bad_usb) {
furi_assert(bad_usb);
return bad_usb->view;
}
void bad_kb_view_set_button_callback(BadKb* bad_kb, BadKbButtonCallback callback, void* context) {
furi_assert(bad_kb);
void bad_usb_view_set_button_callback(
BadUsb* bad_usb,
BadUsbButtonCallback callback,
void* context) {
furi_assert(bad_usb);
furi_assert(callback);
with_view_model(
bad_kb->view,
BadKbModel * model,
bad_usb->view,
BadUsbModel * model,
{
UNUSED(model);
bad_kb->callback = callback;
bad_kb->context = context;
bad_usb->callback = callback;
bad_usb->context = context;
},
true);
}
void bad_kb_view_set_file_name(BadKb* bad_kb, const char* name) {
void bad_usb_view_set_file_name(BadUsb* bad_usb, const char* name) {
furi_assert(name);
with_view_model(
bad_kb->view, BadKbModel * model, { strlcpy(model->file_name, name, MAX_NAME_LEN); }, true);
bad_usb->view,
BadUsbModel * model,
{ strlcpy(model->file_name, name, MAX_NAME_LEN); },
true);
}
void bad_kb_view_set_layout(BadKb* bad_kb, const char* layout) {
void bad_usb_view_set_layout(BadUsb* bad_usb, const char* layout) {
furi_assert(layout);
with_view_model(
bad_kb->view, BadKbModel * model, { strlcpy(model->layout, layout, MAX_NAME_LEN); }, true);
bad_usb->view,
BadUsbModel * model,
{ strlcpy(model->layout, layout, MAX_NAME_LEN); },
true);
}
void bad_kb_view_set_state(BadKb* bad_kb, BadKbState* st) {
void bad_usb_view_set_state(BadUsb* bad_usb, BadUsbState* st) {
furi_assert(st);
with_view_model(
bad_kb->view,
BadKbModel * model,
bad_usb->view,
BadUsbModel * model,
{
memcpy(&(model->state), st, sizeof(BadKbState));
memcpy(&(model->state), st, sizeof(BadUsbState));
model->anim_frame ^= 1;
if(model->state.state == BadKbStatePaused) {
if(model->state.state == BadUsbStatePaused) {
model->pause_wait = false;
}
},
true);
}
void bad_kb_view_set_interface(BadKb* bad_kb, BadKbHidInterface interface) {
with_view_model(bad_kb->view, BadKbModel * model, { model->interface = interface; }, true);
void bad_usb_view_set_interface(BadUsb* bad_usb, BadUsbHidInterface interface) {
with_view_model(bad_usb->view, BadUsbModel * model, { model->interface = interface; }, true);
}
bool bad_kb_view_is_idle_state(BadKb* bad_kb) {
bool bad_usb_view_is_idle_state(BadUsb* bad_usb) {
bool is_idle = false;
with_view_model(
bad_kb->view,
BadKbModel * model,
bad_usb->view,
BadUsbModel * model,
{
if((model->state.state == BadKbStateIdle) || (model->state.state == BadKbStateDone) ||
(model->state.state == BadKbStateNotConnected)) {
if((model->state.state == BadUsbStateIdle) ||
(model->state.state == BadUsbStateDone) ||
(model->state.state == BadUsbStateNotConnected)) {
is_idle = true;
}
},

View File

@@ -0,0 +1,28 @@
#pragma once
#include <gui/view.h>
#include "../helpers/ducky_script.h"
typedef struct BadUsb BadUsb;
typedef void (*BadUsbButtonCallback)(InputKey key, void* context);
BadUsb* bad_usb_view_alloc(void);
void bad_usb_view_free(BadUsb* bad_usb);
View* bad_usb_view_get_view(BadUsb* bad_usb);
void bad_usb_view_set_button_callback(
BadUsb* bad_usb,
BadUsbButtonCallback callback,
void* context);
void bad_usb_view_set_file_name(BadUsb* bad_usb, const char* name);
void bad_usb_view_set_layout(BadUsb* bad_usb, const char* layout);
void bad_usb_view_set_state(BadUsb* bad_usb, BadUsbState* st);
void bad_usb_view_set_interface(BadUsb* bad_usb, BadUsbHidInterface interface);
bool bad_usb_view_is_idle_state(BadUsb* bad_usb);

View File

@@ -34,7 +34,7 @@ static const DolphinDeedWeight dolphin_deed_weights[] = {
{2, DolphinAppIbutton}, // DolphinDeedIbuttonEmulate
{2, DolphinAppIbutton}, // DolphinDeedIbuttonAdd
{3, DolphinAppBadKb}, // DolphinDeedBadKbPlayScript
{3, DolphinAppBadUsb}, // DolphinDeedBadUsbPlayScript
{3, DolphinAppPlugin}, // DolphinDeedU2fAuthorized
@@ -54,7 +54,7 @@ static uint8_t dolphin_deed_limits[] = {
69, // DolphinAppNfc
69, // DolphinAppIr
69, // DolphinAppIbutton
69, // DolphinAppBadKb
69, // DolphinAppBadUsb
69, // DolphinAppPlugin
};

View File

@@ -12,7 +12,7 @@ typedef enum {
DolphinAppNfc,
DolphinAppIr,
DolphinAppIbutton,
DolphinAppBadKb,
DolphinAppBadUsb,
DolphinAppPlugin,
DolphinAppMAX,
} DolphinApp;
@@ -50,7 +50,7 @@ typedef enum {
DolphinDeedIbuttonEmulate,
DolphinDeedIbuttonAdd,
DolphinDeedBadKbPlayScript,
DolphinDeedBadUsbPlayScript,
DolphinDeedU2fAuthorized,

View File

Before

Width:  |  Height:  |  Size: 96 B

After

Width:  |  Height:  |  Size: 96 B

View File

Before

Width:  |  Height:  |  Size: 145 B

After

Width:  |  Height:  |  Size: 145 B

View File

Before

Width:  |  Height:  |  Size: 132 B

After

Width:  |  Height:  |  Size: 132 B

Some files were not shown because too many files have changed in this diff Show More