BadUSB: BLE, media keys, Fn/Globe key commands (#3403)

* BadUSB: media keys, GLOBE command
* f18 api table fix
* BadUSB over BLE
* Made PVS happy

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
Nikolay Minaylov 2024-03-25 11:39:33 +03:00 committed by GitHub
parent f633f476c8
commit 6de2934394
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 637 additions and 171 deletions

View file

@ -7,7 +7,7 @@ App(
icon="A_BadUsb_14",
order=70,
resources="resources",
fap_libs=["assets"],
fap_libs=["assets", "ble_profile"],
fap_icon="icon.png",
fap_category="USB",
)

View file

@ -1,11 +1,14 @@
#include "bad_usb_app_i.h"
#include "bad_usb_settings_filename.h"
#include <furi.h>
#include <furi_hal.h>
#include <storage/storage.h>
#include <lib/toolbox/path.h>
#include <flipper_format/flipper_format.h>
#define BAD_USB_SETTINGS_PATH BAD_USB_APP_BASE_FOLDER "/" BAD_USB_SETTINGS_FILE_NAME
#define BAD_USB_SETTINGS_PATH BAD_USB_APP_BASE_FOLDER "/.badusb.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_usb_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
@ -26,46 +29,69 @@ static void bad_usb_app_tick_event_callback(void* context) {
}
static void bad_usb_load_settings(BadUsbApp* app) {
File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
char chr;
while((storage_file_read(settings_file, &chr, 1) == 1) &&
!storage_file_eof(settings_file) && !isspace(chr)) {
furi_string_push_back(app->keyboard_layout, chr);
}
} else {
furi_string_reset(app->keyboard_layout);
}
storage_file_close(settings_file);
storage_file_free(settings_file);
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff = flipper_format_file_alloc(storage);
bool state = false;
FuriString* temp_str = furi_string_alloc();
uint32_t version = 0;
uint32_t interface = 0;
if(flipper_format_file_open_existing(fff, BAD_USB_SETTINGS_PATH)) {
do {
if(!flipper_format_read_header(fff, temp_str, &version)) break;
if((strcmp(furi_string_get_cstr(temp_str), BAD_USB_SETTINGS_FILE_TYPE) != 0) ||
(version != BAD_USB_SETTINGS_VERSION))
break;
if(!flipper_format_read_string(fff, "layout", temp_str)) break;
if(!flipper_format_read_uint32(fff, "interface", &interface, 1)) break;
if(interface > BadUsbHidInterfaceBle) break;
state = true;
} while(0);
}
flipper_format_free(fff);
furi_record_close(RECORD_STORAGE);
if(state) {
furi_string_set(app->keyboard_layout, temp_str);
app->interface = interface;
if(!furi_string_empty(app->keyboard_layout)) {
Storage* fs_api = furi_record_open(RECORD_STORAGE);
FileInfo layout_file_info;
FS_Error file_check_err = storage_common_stat(
fs_api, furi_string_get_cstr(app->keyboard_layout), &layout_file_info);
furi_record_close(RECORD_STORAGE);
if(file_check_err != FSE_OK) {
furi_string_reset(app->keyboard_layout);
return;
}
if(layout_file_info.size != 256) {
furi_string_reset(app->keyboard_layout);
if((file_check_err != FSE_OK) || (layout_file_info.size != 256)) {
furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT);
}
} else {
furi_string_set(app->keyboard_layout, BAD_USB_SETTINGS_DEFAULT_LAYOUT);
app->interface = BadUsbHidInterfaceUsb;
}
furi_string_free(temp_str);
}
static void bad_usb_save_settings(BadUsbApp* app) {
File* settings_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
if(storage_file_open(settings_file, BAD_USB_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) {
storage_file_write(
settings_file,
furi_string_get_cstr(app->keyboard_layout),
furi_string_size(app->keyboard_layout));
storage_file_write(settings_file, "\n", 1);
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff = flipper_format_file_alloc(storage);
if(flipper_format_file_open_always(fff, BAD_USB_SETTINGS_PATH)) {
do {
if(!flipper_format_write_header_cstr(
fff, BAD_USB_SETTINGS_FILE_TYPE, BAD_USB_SETTINGS_VERSION))
break;
if(!flipper_format_write_string(fff, "layout", app->keyboard_layout)) break;
uint32_t interface_id = app->interface;
if(!flipper_format_write_uint32(fff, "interface", (const uint32_t*)&interface_id, 1))
break;
} while(0);
}
storage_file_close(settings_file);
storage_file_free(settings_file);
flipper_format_free(fff);
furi_record_close(RECORD_STORAGE);
}
BadUsbApp* bad_usb_app_alloc(char* arg) {
@ -103,13 +129,15 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
view_dispatcher_add_view(
app->view_dispatcher, BadUsbAppViewError, widget_get_view(app->widget));
app->submenu = submenu_alloc();
app->var_item_list = variable_item_list_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadUsbAppViewConfig, submenu_get_view(app->submenu));
app->view_dispatcher,
BadUsbAppViewConfig,
variable_item_list_get_view(app->var_item_list));
app->bad_usb_view = bad_usb_alloc();
app->bad_usb_view = bad_usb_view_alloc();
view_dispatcher_add_view(
app->view_dispatcher, BadUsbAppViewWork, bad_usb_get_view(app->bad_usb_view));
app->view_dispatcher, BadUsbAppViewWork, bad_usb_view_get_view(app->bad_usb_view));
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
@ -122,8 +150,6 @@ BadUsbApp* bad_usb_app_alloc(char* arg) {
furi_check(furi_hal_usb_set_config(NULL, NULL));
if(!furi_string_empty(app->file_path)) {
app->bad_usb_script = bad_usb_script_open(app->file_path);
bad_usb_script_set_keyboard_layout(app->bad_usb_script, app->keyboard_layout);
scene_manager_next_scene(app->scene_manager, BadUsbSceneWork);
} else {
furi_string_set(app->file_path, BAD_USB_APP_BASE_FOLDER);
@ -144,15 +170,15 @@ void bad_usb_app_free(BadUsbApp* app) {
// Views
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewWork);
bad_usb_free(app->bad_usb_view);
bad_usb_view_free(app->bad_usb_view);
// Custom Widget
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewError);
widget_free(app->widget);
// Submenu
// Config menu
view_dispatcher_remove_view(app->view_dispatcher, BadUsbAppViewConfig);
submenu_free(app->submenu);
variable_item_list_free(app->var_item_list);
// View dispatcher
view_dispatcher_free(app->view_dispatcher);

View file

@ -3,12 +3,12 @@
#include "bad_usb_app.h"
#include "scenes/bad_usb_scene.h"
#include "helpers/ducky_script.h"
#include "helpers/bad_usb_hid.h"
#include <gui/gui.h>
#include <assets_icons.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <gui/modules/submenu.h>
#include <dialogs/dialogs.h>
#include <notification/notification_messages.h>
#include <gui/modules/variable_item_list.h>
@ -33,7 +33,7 @@ struct BadUsbApp {
NotificationApp* notifications;
DialogsApp* dialogs;
Widget* widget;
Submenu* submenu;
VariableItemList* var_item_list;
BadUsbAppError error;
FuriString* file_path;
@ -41,6 +41,7 @@ struct BadUsbApp {
BadUsb* bad_usb_view;
BadUsbScript* bad_usb_script;
BadUsbHidInterface interface;
FuriHalUsbInterface* usb_if_prev;
};

View file

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

View file

@ -0,0 +1,226 @@
#include "bad_usb_hid.h"
#include <extra_profiles/hid_profile.h>
#include <bt/bt_service/bt.h>
#include <storage/storage.h>
#define TAG "BadUSB HID"
#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys"
void* hid_usb_init(FuriHalUsbHidConfig* hid_cfg) {
furi_check(furi_hal_usb_set_config(&usb_hid, hid_cfg));
return NULL;
}
void hid_usb_deinit(void* inst) {
UNUSED(inst);
furi_check(furi_hal_usb_set_config(NULL, NULL));
}
void hid_usb_set_state_callback(void* inst, HidStateCallback cb, void* context) {
UNUSED(inst);
furi_hal_hid_set_state_callback(cb, context);
}
bool hid_usb_is_connected(void* inst) {
UNUSED(inst);
return furi_hal_hid_is_connected();
}
bool hid_usb_kb_press(void* inst, uint16_t button) {
UNUSED(inst);
return furi_hal_hid_kb_press(button);
}
bool hid_usb_kb_release(void* inst, uint16_t button) {
UNUSED(inst);
return furi_hal_hid_kb_release(button);
}
bool hid_usb_consumer_press(void* inst, uint16_t button) {
UNUSED(inst);
return furi_hal_hid_consumer_key_press(button);
}
bool hid_usb_consumer_release(void* inst, uint16_t button) {
UNUSED(inst);
return furi_hal_hid_consumer_key_release(button);
}
bool hid_usb_release_all(void* inst) {
UNUSED(inst);
bool state = furi_hal_hid_kb_release_all();
state &= furi_hal_hid_consumer_key_release_all();
return state;
}
uint8_t hid_usb_get_led_state(void* inst) {
UNUSED(inst);
return furi_hal_hid_get_led_state();
}
static const BadUsbHidApi hid_api_usb = {
.init = hid_usb_init,
.deinit = hid_usb_deinit,
.set_state_callback = hid_usb_set_state_callback,
.is_connected = hid_usb_is_connected,
.kb_press = hid_usb_kb_press,
.kb_release = hid_usb_kb_release,
.consumer_press = hid_usb_consumer_press,
.consumer_release = hid_usb_consumer_release,
.release_all = hid_usb_release_all,
.get_led_state = hid_usb_get_led_state,
};
typedef struct {
Bt* bt;
FuriHalBleProfileBase* profile;
HidStateCallback state_callback;
void* callback_context;
bool is_connected;
} BleHidInstance;
static const BleProfileHidParams ble_hid_params = {
.device_name_prefix = "BadUSB",
.mac_xor = 0x0002,
};
static void hid_ble_connection_status_callback(BtStatus status, void* context) {
furi_assert(context);
BleHidInstance* ble_hid = context;
ble_hid->is_connected = (status == BtStatusConnected);
if(ble_hid->state_callback) {
ble_hid->state_callback(ble_hid->is_connected, ble_hid->callback_context);
}
}
void* hid_ble_init(FuriHalUsbHidConfig* hid_cfg) {
UNUSED(hid_cfg);
BleHidInstance* ble_hid = malloc(sizeof(BleHidInstance));
ble_hid->bt = furi_record_open(RECORD_BT);
bt_disconnect(ble_hid->bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
bt_keys_storage_set_storage_path(ble_hid->bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
ble_hid->profile = bt_profile_start(ble_hid->bt, ble_profile_hid, (void*)&ble_hid_params);
furi_check(ble_hid->profile);
furi_hal_bt_start_advertising();
bt_set_status_changed_callback(ble_hid->bt, hid_ble_connection_status_callback, ble_hid);
return ble_hid;
}
void hid_ble_deinit(void* inst) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
bt_set_status_changed_callback(ble_hid->bt, NULL, NULL);
bt_disconnect(ble_hid->bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
bt_keys_storage_set_default_path(ble_hid->bt);
furi_check(bt_profile_restore_default(ble_hid->bt));
furi_record_close(RECORD_BT);
free(ble_hid);
}
void hid_ble_set_state_callback(void* inst, HidStateCallback cb, void* context) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
ble_hid->state_callback = cb;
ble_hid->callback_context = context;
}
bool hid_ble_is_connected(void* inst) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_hid->is_connected;
}
bool hid_ble_kb_press(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_kb_press(ble_hid->profile, button);
}
bool hid_ble_kb_release(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_kb_release(ble_hid->profile, button);
}
bool hid_ble_consumer_press(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_consumer_key_press(ble_hid->profile, button);
}
bool hid_ble_consumer_release(void* inst, uint16_t button) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
return ble_profile_hid_consumer_key_release(ble_hid->profile, button);
}
bool hid_ble_release_all(void* inst) {
BleHidInstance* ble_hid = inst;
furi_assert(ble_hid);
bool state = ble_profile_hid_kb_release_all(ble_hid->profile);
state &= ble_profile_hid_consumer_key_release_all(ble_hid->profile);
return state;
}
uint8_t hid_ble_get_led_state(void* inst) {
UNUSED(inst);
FURI_LOG_W(TAG, "hid_ble_get_led_state not implemented");
return 0;
}
static const BadUsbHidApi hid_api_ble = {
.init = hid_ble_init,
.deinit = hid_ble_deinit,
.set_state_callback = hid_ble_set_state_callback,
.is_connected = hid_ble_is_connected,
.kb_press = hid_ble_kb_press,
.kb_release = hid_ble_kb_release,
.consumer_press = hid_ble_consumer_press,
.consumer_release = hid_ble_consumer_release,
.release_all = hid_ble_release_all,
.get_led_state = hid_ble_get_led_state,
};
const BadUsbHidApi* bad_usb_hid_get_interface(BadUsbHidInterface interface) {
if(interface == BadUsbHidInterfaceUsb) {
return &hid_api_usb;
} else {
return &hid_api_ble;
}
}
void bad_usb_hid_ble_remove_pairing(void) {
Bt* bt = furi_record_open(RECORD_BT);
bt_disconnect(bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
furi_hal_bt_stop_advertising();
bt_keys_storage_set_storage_path(bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
bt_forget_bonded_devices(bt);
// Wait 2nd core to update nvm storage
furi_delay_ms(200);
bt_keys_storage_set_default_path(bt);
furi_check(bt_profile_restore_default(bt));
furi_record_close(RECORD_BT);
}

View file

@ -0,0 +1,35 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <furi.h>
#include <furi_hal.h>
typedef enum {
BadUsbHidInterfaceUsb,
BadUsbHidInterfaceBle,
} BadUsbHidInterface;
typedef struct {
void* (*init)(FuriHalUsbHidConfig* hid_cfg);
void (*deinit)(void* inst);
void (*set_state_callback)(void* inst, HidStateCallback cb, void* context);
bool (*is_connected)(void* inst);
bool (*kb_press)(void* inst, uint16_t button);
bool (*kb_release)(void* inst, uint16_t button);
bool (*consumer_press)(void* inst, uint16_t button);
bool (*consumer_release)(void* inst, uint16_t button);
bool (*release_all)(void* inst);
uint8_t (*get_led_state)(void* inst);
} BadUsbHidApi;
const BadUsbHidApi* bad_usb_hid_get_interface(BadUsbHidInterface interface);
void bad_usb_hid_ble_remove_pairing(void);
#ifdef __cplusplus
}
#endif

View file

@ -3,7 +3,6 @@
#include <gui/gui.h>
#include <input/input.h>
#include <lib/toolbox/args.h>
#include <furi_hal_usb_hid.h>
#include <storage/storage.h>
#include "ducky_script.h"
#include "ducky_script_i.h"
@ -71,39 +70,40 @@ bool ducky_get_number(const char* param, uint32_t* val) {
return false;
}
void ducky_numlock_on(void) {
if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) {
furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK);
furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK);
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(const char num) {
bool ducky_numpad_press(BadUsbScript* bad_usb, const char num) {
if((num < '0') || (num > '9')) return false;
uint16_t key = numpad_keys[num - '0'];
furi_hal_hid_kb_press(key);
furi_hal_hid_kb_release(key);
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(const char* charcode) {
bool ducky_altchar(BadUsbScript* bad_usb, const char* charcode) {
uint8_t i = 0;
bool state = false;
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT);
bad_usb->hid->kb_press(bad_usb->hid_inst, KEY_MOD_LEFT_ALT);
while(!ducky_is_line_end(charcode[i])) {
state = ducky_numpad_press(charcode[i]);
state = ducky_numpad_press(bad_usb, charcode[i]);
if(state == false) break;
i++;
}
furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT);
bad_usb->hid->kb_release(bad_usb->hid_inst, KEY_MOD_LEFT_ALT);
return state;
}
bool ducky_altstring(const char* param) {
bool ducky_altstring(BadUsbScript* bad_usb, const char* param) {
uint32_t i = 0;
bool state = false;
@ -116,7 +116,7 @@ bool ducky_altstring(const char* param) {
char temp_str[4];
snprintf(temp_str, 4, "%u", param[i]);
state = ducky_altchar(temp_str);
state = ducky_altchar(bad_usb, temp_str);
if(state == false) break;
i++;
}
@ -140,12 +140,12 @@ bool ducky_string(BadUsbScript* bad_usb, const char* param) {
if(param[i] != '\n') {
uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]);
if(keycode != HID_KEYBOARD_NONE) {
furi_hal_hid_kb_press(keycode);
furi_hal_hid_kb_release(keycode);
bad_usb->hid->kb_press(bad_usb->hid_inst, keycode);
bad_usb->hid->kb_release(bad_usb->hid_inst, keycode);
}
} else {
furi_hal_hid_kb_press(HID_KEYBOARD_RETURN);
furi_hal_hid_kb_release(HID_KEYBOARD_RETURN);
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++;
}
@ -163,12 +163,12 @@ static bool ducky_string_next(BadUsbScript* bad_usb) {
if(print_char != '\n') {
uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, print_char);
if(keycode != HID_KEYBOARD_NONE) {
furi_hal_hid_kb_press(keycode);
furi_hal_hid_kb_release(keycode);
bad_usb->hid->kb_press(bad_usb->hid_inst, keycode);
bad_usb->hid->kb_release(bad_usb->hid_inst, keycode);
}
} else {
furi_hal_hid_kb_press(HID_KEYBOARD_RETURN);
furi_hal_hid_kb_release(HID_KEYBOARD_RETURN);
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++;
@ -201,8 +201,8 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, FuriString* line) {
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
key |= ducky_get_keycode(bad_usb, line_tmp, true);
}
furi_hal_hid_kb_press(key);
furi_hal_hid_kb_release(key);
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
return 0;
}
@ -231,6 +231,17 @@ static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) {
return false;
}
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;
@ -265,10 +276,11 @@ static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
}
if(id_set) {
furi_check(furi_hal_usb_set_config(&usb_hid, &bad_usb->hid_cfg));
bad_usb->hid_inst = bad_usb->hid->init(&bad_usb->hid_cfg);
} else {
furi_check(furi_hal_usb_set_config(&usb_hid, NULL));
bad_usb->hid_inst = bad_usb->hid->init(NULL);
}
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);
@ -345,17 +357,6 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
return 0;
}
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 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);
@ -382,8 +383,6 @@ static int32_t bad_usb_worker(void* context) {
bad_usb->line_prev = furi_string_alloc();
bad_usb->string_print = furi_string_alloc();
furi_hal_hid_set_state_callback(bad_usb_hid_state_callback, bad_usb);
while(1) {
if(worker_state == BadUsbStateInit) { // State: initialization
if(storage_file_open(
@ -392,7 +391,7 @@ static int32_t bad_usb_worker(void* context) {
FSAM_READ,
FSOM_OPEN_EXISTING)) {
if((ducky_script_preload(bad_usb, script_file)) && (bad_usb->st.line_nb > 0)) {
if(furi_hal_hid_is_connected()) {
if(bad_usb->hid->is_connected(bad_usb->hid_inst)) {
worker_state = BadUsbStateIdle; // Ready to run
} else {
worker_state = BadUsbStateNotConnected; // USB not connected
@ -408,7 +407,8 @@ static int32_t bad_usb_worker(void* context) {
} else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected
uint32_t flags = bad_usb_flags_get(
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtStartStop, FuriWaitForever);
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop,
FuriWaitForever);
if(flags & WorkerEvtEnd) {
break;
@ -490,10 +490,10 @@ static int32_t bad_usb_worker(void* context) {
break;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateIdle; // Stop executing script
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // USB disconnected
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
pause_state = BadUsbStateRunning;
worker_state = BadUsbStatePaused; // Pause
@ -513,12 +513,12 @@ static int32_t bad_usb_worker(void* context) {
delay_val = 0;
worker_state = BadUsbStateScriptError;
bad_usb->st.state = worker_state;
furi_hal_hid_kb_release_all();
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;
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
continue;
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays
delay_val = bad_usb->defdelay;
@ -546,7 +546,7 @@ static int32_t bad_usb_worker(void* context) {
worker_state = BadUsbStateRunning;
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // USB disconnected
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
}
bad_usb->st.state = worker_state;
continue;
@ -561,11 +561,11 @@ static int32_t bad_usb_worker(void* context) {
} else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateIdle; // Stop executing script
bad_usb->st.state = worker_state;
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // USB disconnected
bad_usb->st.state = worker_state;
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
if(pause_state == BadUsbStateRunning) {
if(delay_val > 0) {
@ -595,10 +595,10 @@ static int32_t bad_usb_worker(void* context) {
break;
} else if(flags & WorkerEvtStartStop) {
worker_state = BadUsbStateIdle; // Stop executing script
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtDisconnect) {
worker_state = BadUsbStateNotConnected; // USB disconnected
furi_hal_hid_kb_release_all();
bad_usb->hid->release_all(bad_usb->hid_inst);
} else if(flags & WorkerEvtPauseResume) {
pause_state = BadUsbStateStringDelay;
worker_state = BadUsbStatePaused; // Pause
@ -628,7 +628,8 @@ static int32_t bad_usb_worker(void* context) {
}
}
furi_hal_hid_set_state_callback(NULL, NULL);
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);
@ -647,7 +648,7 @@ static void bad_usb_script_set_default_keyboard_layout(BadUsbScript* bad_usb) {
memcpy(bad_usb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_usb->layout)));
}
BadUsbScript* bad_usb_script_open(FuriString* file_path) {
BadUsbScript* bad_usb_script_open(FuriString* file_path, BadUsbHidInterface interface) {
furi_assert(file_path);
BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript));
@ -657,6 +658,7 @@ BadUsbScript* bad_usb_script_open(FuriString* file_path) {
bad_usb->st.state = BadUsbStateInit;
bad_usb->st.error[0] = '\0';
bad_usb->hid = bad_usb_hid_get_interface(interface);
bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb);
furi_thread_start(bad_usb->thread);

View file

@ -6,6 +6,7 @@ extern "C" {
#include <furi.h>
#include <furi_hal.h>
#include "bad_usb_hid.h"
typedef enum {
BadUsbStateInit,
@ -33,7 +34,7 @@ typedef struct {
typedef struct BadUsbScript BadUsbScript;
BadUsbScript* bad_usb_script_open(FuriString* file_path);
BadUsbScript* bad_usb_script_open(FuriString* file_path, BadUsbHidInterface interface);
void bad_usb_script_close(BadUsbScript* bad_usb);

View file

@ -1,5 +1,4 @@
#include <furi_hal.h>
#include <furi_hal_usb_hid.h>
#include "ducky_script.h"
#include "ducky_script_i.h"
@ -93,9 +92,9 @@ static int32_t ducky_fnc_sysrq(BadUsbScript* bad_usb, const char* line, int32_t
line = &line[ducky_get_command_len(line) + 1];
uint16_t key = ducky_get_keycode(bad_usb, line, true);
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
furi_hal_hid_kb_press(key);
furi_hal_hid_kb_release_all();
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;
}
@ -103,8 +102,8 @@ static int32_t ducky_fnc_altchar(BadUsbScript* bad_usb, const char* line, int32_
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
ducky_numlock_on();
bool state = ducky_altchar(line);
ducky_numlock_on(bad_usb);
bool state = ducky_altchar(bad_usb, line);
if(!state) {
return ducky_error(bad_usb, "Invalid altchar %s", line);
}
@ -115,8 +114,8 @@ static int32_t ducky_fnc_altstring(BadUsbScript* bad_usb, const char* line, int3
UNUSED(param);
line = &line[ducky_get_command_len(line) + 1];
ducky_numlock_on();
bool state = ducky_altstring(line);
ducky_numlock_on(bad_usb);
bool state = ducky_altstring(bad_usb, line);
if(!state) {
return ducky_error(bad_usb, "Invalid altstring %s", line);
}
@ -135,7 +134,7 @@ static int32_t ducky_fnc_hold(BadUsbScript* bad_usb, const char* line, int32_t p
if(bad_usb->key_hold_nb > (HID_KB_MAX_KEYS - 1)) {
return ducky_error(bad_usb, "Too many keys are hold");
}
furi_hal_hid_kb_press(key);
bad_usb->hid->kb_press(bad_usb->hid_inst, key);
return 0;
}
@ -151,7 +150,36 @@ static int32_t ducky_fnc_release(BadUsbScript* bad_usb, const char* line, int32_
return ducky_error(bad_usb, "No keys are hold");
}
bad_usb->key_hold_nb--;
furi_hal_hid_kb_release(key);
bad_usb->hid->kb_release(bad_usb->hid_inst, key);
return 0;
}
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_usb, "No keycode defined for %s", line);
}
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(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_usb, line, true);
if(key == HID_KEYBOARD_NONE) {
return ducky_error(bad_usb, "No keycode defined for %s", line);
}
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;
}
@ -183,6 +211,8 @@ static const DuckyCmd ducky_commands[] = {
{"HOLD", ducky_fnc_hold, -1},
{"RELEASE", ducky_fnc_release, -1},
{"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1},
{"MEDIA", ducky_fnc_media, -1},
{"GLOBE", ducky_fnc_globe, -1},
};
#define TAG "BadUsb"

View file

@ -7,6 +7,7 @@ extern "C" {
#include <furi.h>
#include <furi_hal.h>
#include "ducky_script.h"
#include "bad_usb_hid.h"
#define SCRIPT_STATE_ERROR (-1)
#define SCRIPT_STATE_END (-2)
@ -19,6 +20,8 @@ extern "C" {
struct BadUsbScript {
FuriHalUsbHidConfig hid_cfg;
const BadUsbHidApi* hid;
void* hid_inst;
FuriThread* thread;
BadUsbState st;
@ -50,15 +53,17 @@ bool ducky_is_line_end(const char chr);
uint16_t ducky_get_keycode_by_name(const char* param);
uint16_t ducky_get_media_keycode_by_name(const char* param);
bool ducky_get_number(const char* param, uint32_t* val);
void ducky_numlock_on(void);
void ducky_numlock_on(BadUsbScript* bad_usb);
bool ducky_numpad_press(const char num);
bool ducky_numpad_press(BadUsbScript* bad_usb, const char num);
bool ducky_altchar(const char* charcode);
bool ducky_altchar(BadUsbScript* bad_usb, const char* charcode);
bool ducky_altstring(const char* param);
bool ducky_altstring(BadUsbScript* bad_usb, const char* param);
bool ducky_string(BadUsbScript* bad_usb, const char* param);

View file

@ -1,5 +1,4 @@
#include <furi_hal.h>
#include <furi_hal_usb_hid.h>
#include "ducky_script_i.h"
typedef struct {
@ -78,6 +77,37 @@ static const DuckyKey ducky_keys[] = {
{"F24", HID_KEYBOARD_F24},
};
static const DuckyKey ducky_media_keys[] = {
{"POWER", HID_CONSUMER_POWER},
{"REBOOT", HID_CONSUMER_RESET},
{"SLEEP", HID_CONSUMER_SLEEP},
{"LOGOFF", HID_CONSUMER_AL_LOGOFF},
{"EXIT", HID_CONSUMER_AC_EXIT},
{"HOME", HID_CONSUMER_AC_HOME},
{"BACK", HID_CONSUMER_AC_BACK},
{"FORWARD", HID_CONSUMER_AC_FORWARD},
{"REFRESH", HID_CONSUMER_AC_REFRESH},
{"SNAPSHOT", HID_CONSUMER_SNAPSHOT},
{"PLAY", HID_CONSUMER_PLAY},
{"PAUSE", HID_CONSUMER_PAUSE},
{"PLAY_PAUSE", HID_CONSUMER_PLAY_PAUSE},
{"NEXT_TRACK", HID_CONSUMER_SCAN_NEXT_TRACK},
{"PREV_TRACK", HID_CONSUMER_SCAN_PREVIOUS_TRACK},
{"STOP", HID_CONSUMER_STOP},
{"EJECT", HID_CONSUMER_EJECT},
{"MUTE", HID_CONSUMER_MUTE},
{"VOLUME_UP", HID_CONSUMER_VOLUME_INCREMENT},
{"VOLUME_DOWN", HID_CONSUMER_VOLUME_DECREMENT},
{"FN", HID_CONSUMER_FN_GLOBE},
{"BRIGHT_UP", HID_CONSUMER_BRIGHTNESS_INCREMENT},
{"BRIGHT_DOWN", HID_CONSUMER_BRIGHTNESS_DECREMENT},
};
uint16_t ducky_get_keycode_by_name(const char* param) {
for(size_t i = 0; i < COUNT_OF(ducky_keys); i++) {
size_t key_cmd_len = strlen(ducky_keys[i].name);
@ -89,3 +119,15 @@ uint16_t ducky_get_keycode_by_name(const char* param) {
return HID_KEYBOARD_NONE;
}
uint16_t ducky_get_media_keycode_by_name(const char* param) {
for(size_t i = 0; i < COUNT_OF(ducky_media_keys); i++) {
size_t key_cmd_len = strlen(ducky_media_keys[i].name);
if((strncmp(param, ducky_media_keys[i].name, key_cmd_len) == 0) &&
(ducky_is_line_end(param[key_cmd_len]))) {
return ducky_media_keys[i].keycode;
}
}
return HID_CONSUMER_UNASSIGNED;
}

View file

@ -1,29 +1,62 @@
#include "../bad_usb_app_i.h"
#include "furi_hal_power.h"
#include "furi_hal_usb.h"
enum SubmenuIndex {
SubmenuIndexKeyboardLayout,
ConfigIndexKeyboardLayout,
ConfigIndexInterface,
ConfigIndexBleUnpair,
};
void bad_usb_scene_config_submenu_callback(void* context, uint32_t index) {
const char* const interface_mode_text[2] = {
"USB",
"BLE",
};
void bad_usb_scene_config_select_callback(void* context, uint32_t index) {
BadUsbApp* bad_usb = context;
if(index != ConfigIndexInterface) {
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, index);
}
}
void bad_usb_scene_config_interface_callback(VariableItem* item) {
BadUsbApp* bad_usb = variable_item_get_context(item);
furi_assert(bad_usb);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, interface_mode_text[index]);
bad_usb->interface = index;
view_dispatcher_send_custom_event(bad_usb->view_dispatcher, ConfigIndexInterface);
}
static void draw_menu(BadUsbApp* bad_usb) {
VariableItemList* var_item_list = bad_usb->var_item_list;
variable_item_list_reset(var_item_list);
variable_item_list_add(var_item_list, "Keyboard Layout (global)", 0, NULL, NULL);
VariableItem* item = variable_item_list_add(
var_item_list, "Interface", 2, bad_usb_scene_config_interface_callback, bad_usb);
if(bad_usb->interface == BadUsbHidInterfaceUsb) {
variable_item_set_current_value_index(item, 0);
variable_item_set_current_value_text(item, interface_mode_text[0]);
} else {
variable_item_set_current_value_index(item, 1);
variable_item_set_current_value_text(item, interface_mode_text[1]);
variable_item_list_add(var_item_list, "Remove Pairing", 0, NULL, NULL);
}
}
void bad_usb_scene_config_on_enter(void* context) {
BadUsbApp* bad_usb = context;
Submenu* submenu = bad_usb->submenu;
VariableItemList* var_item_list = bad_usb->var_item_list;
submenu_add_item(
submenu,
"Keyboard Layout (global)",
SubmenuIndexKeyboardLayout,
bad_usb_scene_config_submenu_callback,
bad_usb);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(bad_usb->scene_manager, BadUsbSceneConfig));
variable_item_list_set_enter_callback(
var_item_list, bad_usb_scene_config_select_callback, bad_usb);
draw_menu(bad_usb);
variable_item_list_set_selected_item(var_item_list, 0);
view_dispatcher_switch_to_view(bad_usb->view_dispatcher, BadUsbAppViewConfig);
}
@ -33,10 +66,13 @@ bool bad_usb_scene_config_on_event(void* context, SceneManagerEvent event) {
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(bad_usb->scene_manager, BadUsbSceneConfig, event.event);
consumed = true;
if(event.event == SubmenuIndexKeyboardLayout) {
if(event.event == ConfigIndexKeyboardLayout) {
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneConfigLayout);
} else if(event.event == ConfigIndexInterface) {
draw_menu(bad_usb);
} else if(event.event == ConfigIndexBleUnpair) {
bad_usb_hid_ble_remove_pairing();
} else {
furi_crash("Unknown key type");
}
@ -47,7 +83,7 @@ bool bad_usb_scene_config_on_event(void* context, SceneManagerEvent event) {
void bad_usb_scene_config_on_exit(void* context) {
BadUsbApp* bad_usb = context;
Submenu* submenu = bad_usb->submenu;
VariableItemList* var_item_list = bad_usb->var_item_list;
submenu_reset(submenu);
variable_item_list_reset(var_item_list);
}

View file

@ -1,6 +1,5 @@
#include "../bad_usb_app_i.h"
#include "furi_hal_power.h"
#include "furi_hal_usb.h"
#include <storage/storage.h>
static bool bad_usb_layout_select(BadUsbApp* bad_usb) {

View file

@ -1,6 +1,5 @@
#include "../bad_usb_app_i.h"
#include <furi_hal_power.h>
#include <furi_hal_usb.h>
#include <storage/storage.h>
static bool bad_usb_file_select(BadUsbApp* bad_usb) {
@ -28,9 +27,6 @@ void bad_usb_scene_file_select_on_enter(void* context) {
}
if(bad_usb_file_select(bad_usb)) {
bad_usb->bad_usb_script = bad_usb_script_open(bad_usb->file_path);
bad_usb_script_set_keyboard_layout(bad_usb->bad_usb_script, bad_usb->keyboard_layout);
scene_manager_next_scene(bad_usb->scene_manager, BadUsbSceneWork);
} else {
view_dispatcher_stop(bad_usb->view_dispatcher);

View file

@ -16,7 +16,10 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == InputKeyLeft) {
if(bad_usb_is_idle_state(app->bad_usb_view)) {
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;
@ -28,7 +31,7 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script));
bad_usb_view_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script));
}
return consumed;
}
@ -36,21 +39,24 @@ bool bad_usb_scene_work_on_event(void* context, SceneManagerEvent event) {
void bad_usb_scene_work_on_enter(void* context) {
BadUsbApp* app = context;
app->bad_usb_script = bad_usb_script_open(app->file_path, app->interface);
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_set_file_name(app->bad_usb_view, furi_string_get_cstr(file_name));
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_set_layout(app->bad_usb_view, furi_string_get_cstr(layout));
bad_usb_view_set_layout(app->bad_usb_view, furi_string_get_cstr(layout));
furi_string_free(layout);
bad_usb_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script));
bad_usb_view_set_state(app->bad_usb_view, bad_usb_script_get_state(app->bad_usb_script));
bad_usb_set_button_callback(app->bad_usb_view, bad_usb_scene_work_button_callback, app);
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);
}

View file

@ -66,7 +66,7 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
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 USB");
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "to device");
} else if(state == BadUsbStateWillRun) {
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
canvas_set_font(canvas, FontPrimary);
@ -193,7 +193,7 @@ static bool bad_usb_input_callback(InputEvent* event, void* context) {
return consumed;
}
BadUsb* bad_usb_alloc(void) {
BadUsb* bad_usb_view_alloc(void) {
BadUsb* bad_usb = malloc(sizeof(BadUsb));
bad_usb->view = view_alloc();
@ -205,18 +205,21 @@ BadUsb* bad_usb_alloc(void) {
return bad_usb;
}
void bad_usb_free(BadUsb* bad_usb) {
void bad_usb_view_free(BadUsb* bad_usb) {
furi_assert(bad_usb);
view_free(bad_usb->view);
free(bad_usb);
}
View* bad_usb_get_view(BadUsb* bad_usb) {
View* bad_usb_view_get_view(BadUsb* bad_usb) {
furi_assert(bad_usb);
return bad_usb->view;
}
void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback, void* context) {
void bad_usb_view_set_button_callback(
BadUsb* bad_usb,
BadUsbButtonCallback callback,
void* context) {
furi_assert(bad_usb);
furi_assert(callback);
with_view_model(
@ -230,7 +233,7 @@ void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback,
true);
}
void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) {
void bad_usb_view_set_file_name(BadUsb* bad_usb, const char* name) {
furi_assert(name);
with_view_model(
bad_usb->view,
@ -239,7 +242,7 @@ void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) {
true);
}
void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) {
void bad_usb_view_set_layout(BadUsb* bad_usb, const char* layout) {
furi_assert(layout);
with_view_model(
bad_usb->view,
@ -248,7 +251,7 @@ void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) {
true);
}
void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) {
void bad_usb_view_set_state(BadUsb* bad_usb, BadUsbState* st) {
furi_assert(st);
with_view_model(
bad_usb->view,
@ -263,7 +266,7 @@ void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) {
true);
}
bool bad_usb_is_idle_state(BadUsb* bad_usb) {
bool bad_usb_view_is_idle_state(BadUsb* bad_usb) {
bool is_idle = false;
with_view_model(
bad_usb->view,

View file

@ -6,18 +6,21 @@
typedef struct BadUsb BadUsb;
typedef void (*BadUsbButtonCallback)(InputKey key, void* context);
BadUsb* bad_usb_alloc(void);
BadUsb* bad_usb_view_alloc(void);
void bad_usb_free(BadUsb* bad_usb);
void bad_usb_view_free(BadUsb* bad_usb);
View* bad_usb_get_view(BadUsb* bad_usb);
View* bad_usb_view_get_view(BadUsb* bad_usb);
void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback, void* context);
void bad_usb_view_set_button_callback(
BadUsb* bad_usb,
BadUsbButtonCallback callback,
void* context);
void bad_usb_set_file_name(BadUsb* bad_usb, const char* name);
void bad_usb_view_set_file_name(BadUsb* bad_usb, const char* name);
void bad_usb_set_layout(BadUsb* bad_usb, const char* layout);
void bad_usb_view_set_layout(BadUsb* bad_usb, const char* layout);
void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st);
void bad_usb_view_set_state(BadUsb* bad_usb, BadUsbState* st);
bool bad_usb_is_idle_state(BadUsb* bad_usb);
bool bad_usb_view_is_idle_state(BadUsb* bad_usb);

View file

@ -79,15 +79,7 @@ Up to 5 keys can be hold simultaneously.
| HOLD | Special key or single character | Press and hold key until RELEASE command |
| RELEASE | Special key or single character | Release key |
## Wait for button press
Will wait indefinitely for a button to be pressed
| Command | Parameters | Notes |
| --------------------- | ------------ | --------------------------------------------------------------------- |
| WAIT_FOR_BUTTON_PRESS | None | Will wait for the user to press a button to continue script execution |
### String
## String
| Command | Parameters | Notes |
| ------- | ----------- | ----------------- |
@ -126,7 +118,54 @@ Send [SysRq command](https://en.wikipedia.org/wiki/Magic_SysRq_key)
| ------- | ---------------- | ----- |
| SYSRQ | Single character | |
### USB device ID
## Media keys
Some Media/Consumer Control keys can be pressed with "MEDIA" command
| Command | Parameters | Notes |
| ------- | ------------------------- | ----- |
| MEDIA | Media key, see list below | |
| Key name | Notes |
| ----------------- | ----------------------------- |
| POWER | |
| REBOOT | |
| SLEEP | |
| LOGOFF | |
| EXIT | |
| HOME | |
| BACK | |
| FORWARD | |
| REFRESH | |
| SNAPSHOT | Take photo in a camera app |
| PLAY | |
| PAUSE | |
| PLAY_PAUSE | |
| NEXT_TRACK | |
| PREV_TRACK | |
| STOP | |
| EJECT | |
| MUTE | |
| VOLUME_UP | |
| VOLUME_DOWN | |
| FN | Fn/Globe key on Mac keyboard |
| BRIGHT_UP | Increase display brightness |
| BRIGHT_DOWN | Decrease display brightness |
## Fn/Globe key commands (Mac/iPad)
| Command | Parameters | Notes |
| ------- | ------------------------------- | ----- |
| GLOBE | Special key or single character | |
## Wait for button press
Will wait indefinitely for a button to be pressed
| Command | Parameters | Notes |
| --------------------- | ------------ | --------------------------------------------------------------------- |
| WAIT_FOR_BUTTON_PRESS | None | Will wait for the user to press a button to continue script execution |
## USB device ID
You can set the custom ID of the Flipper USB HID device. ID command should be in the **first line** of script, it is executed before script run.

View file

@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,60.1,,
Version,+,60.2,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
@ -1205,6 +1205,7 @@ Function,+,furi_hal_gpio_init_simple,void,"const GpioPin*, const GpioMode"
Function,+,furi_hal_gpio_remove_int_callback,void,const GpioPin*
Function,+,furi_hal_hid_consumer_key_press,_Bool,uint16_t
Function,+,furi_hal_hid_consumer_key_release,_Bool,uint16_t
Function,+,furi_hal_hid_consumer_key_release_all,_Bool,
Function,+,furi_hal_hid_get_led_state,uint8_t,
Function,+,furi_hal_hid_is_connected,_Bool,
Function,+,furi_hal_hid_kb_press,_Bool,uint16_t

1 entry status name type params
2 Version + 60.1 60.2
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
1205 Function + furi_hal_gpio_remove_int_callback void const GpioPin*
1206 Function + furi_hal_hid_consumer_key_press _Bool uint16_t
1207 Function + furi_hal_hid_consumer_key_release _Bool uint16_t
1208 Function + furi_hal_hid_consumer_key_release_all _Bool
1209 Function + furi_hal_hid_get_led_state uint8_t
1210 Function + furi_hal_hid_is_connected _Bool
1211 Function + furi_hal_hid_kb_press _Bool uint16_t

View file

@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,60.1,,
Version,+,60.2,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
@ -1273,6 +1273,7 @@ Function,+,furi_hal_gpio_init_simple,void,"const GpioPin*, const GpioMode"
Function,+,furi_hal_gpio_remove_int_callback,void,const GpioPin*
Function,+,furi_hal_hid_consumer_key_press,_Bool,uint16_t
Function,+,furi_hal_hid_consumer_key_release,_Bool,uint16_t
Function,+,furi_hal_hid_consumer_key_release_all,_Bool,
Function,+,furi_hal_hid_get_led_state,uint8_t,
Function,+,furi_hal_hid_is_connected,_Bool,
Function,+,furi_hal_hid_kb_press,_Bool,uint16_t

1 entry status name type params
2 Version + 60.1 60.2
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/services/bt/bt_service/bt.h
5 Header + applications/services/cli/cli.h
1273 Function + furi_hal_gpio_remove_int_callback void const GpioPin*
1274 Function + furi_hal_hid_consumer_key_press _Bool uint16_t
1275 Function + furi_hal_hid_consumer_key_release _Bool uint16_t
1276 Function + furi_hal_hid_consumer_key_release_all _Bool
1277 Function + furi_hal_hid_get_led_state uint8_t
1278 Function + furi_hal_hid_is_connected _Bool
1279 Function + furi_hal_hid_kb_press _Bool uint16_t

View file

@ -354,6 +354,13 @@ bool furi_hal_hid_consumer_key_release(uint16_t button) {
return hid_send_report(ReportIdConsumer);
}
bool furi_hal_hid_consumer_key_release_all(void) {
for(uint8_t key_nb = 0; key_nb < HID_CONSUMER_MAX_KEYS; key_nb++) {
hid_report.consumer.btn[key_nb] = 0;
}
return hid_send_report(ReportIdConsumer);
}
static void* hid_set_string_descr(char* str) {
furi_assert(str);

View file

@ -14,6 +14,11 @@ extern "C" {
/** Max number of simultaneously pressed keys (consumer control) */
#define HID_CONSUMER_MAX_KEYS 2
/** OS-specific consumer keys, defined as "Reserved" in HID Usage Tables document */
#define HID_CONSUMER_BRIGHTNESS_INCREMENT 0x006F
#define HID_CONSUMER_BRIGHTNESS_DECREMENT 0x0070
#define HID_CONSUMER_FN_GLOBE 0x029D
#define HID_KEYBOARD_NONE 0x00
/** HID keyboard modifier keys */
@ -259,6 +264,11 @@ bool furi_hal_hid_consumer_key_press(uint16_t button);
*/
bool furi_hal_hid_consumer_key_release(uint16_t button);
/** Clear all pressed consumer keys and send HID report
*
*/
bool furi_hal_hid_consumer_key_release_all(void);
#ifdef __cplusplus
}
#endif