diff --git a/applications/main/bad_usb/application.fam b/applications/main/bad_usb/application.fam index 9844e248d..8d3909fcc 100644 --- a/applications/main/bad_usb/application.fam +++ b/applications/main/bad_usb/application.fam @@ -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", ) diff --git a/applications/main/bad_usb/bad_usb_app.c b/applications/main/bad_usb/bad_usb_app.c index ea97c4487..0cf7f1924 100644 --- a/applications/main/bad_usb/bad_usb_app.c +++ b/applications/main/bad_usb/bad_usb_app.c @@ -1,11 +1,14 @@ #include "bad_usb_app_i.h" -#include "bad_usb_settings_filename.h" #include #include #include #include +#include -#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); diff --git a/applications/main/bad_usb/bad_usb_app_i.h b/applications/main/bad_usb/bad_usb_app_i.h index cf1c02ebc..c12f9ac75 100644 --- a/applications/main/bad_usb/bad_usb_app_i.h +++ b/applications/main/bad_usb/bad_usb_app_i.h @@ -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 #include #include #include -#include #include #include #include @@ -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; }; diff --git a/applications/main/bad_usb/bad_usb_settings_filename.h b/applications/main/bad_usb/bad_usb_settings_filename.h deleted file mode 100644 index 12ba8f31c..000000000 --- a/applications/main/bad_usb/bad_usb_settings_filename.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#define BAD_USB_SETTINGS_FILE_NAME ".badusb.settings" diff --git a/applications/main/bad_usb/helpers/bad_usb_hid.c b/applications/main/bad_usb/helpers/bad_usb_hid.c new file mode 100644 index 000000000..289e3ae8c --- /dev/null +++ b/applications/main/bad_usb/helpers/bad_usb_hid.c @@ -0,0 +1,226 @@ +#include "bad_usb_hid.h" +#include +#include +#include + +#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); +} \ No newline at end of file diff --git a/applications/main/bad_usb/helpers/bad_usb_hid.h b/applications/main/bad_usb/helpers/bad_usb_hid.h new file mode 100644 index 000000000..71d3a58e7 --- /dev/null +++ b/applications/main/bad_usb/helpers/bad_usb_hid.h @@ -0,0 +1,35 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +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 diff --git a/applications/main/bad_usb/helpers/ducky_script.c b/applications/main/bad_usb/helpers/ducky_script.c index 5a32ae433..077b1c37b 100644 --- a/applications/main/bad_usb/helpers/ducky_script.c +++ b/applications/main/bad_usb/helpers/ducky_script.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #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); diff --git a/applications/main/bad_usb/helpers/ducky_script.h b/applications/main/bad_usb/helpers/ducky_script.h index dca61ed4e..9519623f6 100644 --- a/applications/main/bad_usb/helpers/ducky_script.h +++ b/applications/main/bad_usb/helpers/ducky_script.h @@ -6,6 +6,7 @@ extern "C" { #include #include +#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); diff --git a/applications/main/bad_usb/helpers/ducky_script_commands.c b/applications/main/bad_usb/helpers/ducky_script_commands.c index fdf963b40..7f9a48fb2 100644 --- a/applications/main/bad_usb/helpers/ducky_script_commands.c +++ b/applications/main/bad_usb/helpers/ducky_script_commands.c @@ -1,5 +1,4 @@ #include -#include #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" diff --git a/applications/main/bad_usb/helpers/ducky_script_i.h b/applications/main/bad_usb/helpers/ducky_script_i.h index 9c1025b00..bbafdccb6 100644 --- a/applications/main/bad_usb/helpers/ducky_script_i.h +++ b/applications/main/bad_usb/helpers/ducky_script_i.h @@ -7,6 +7,7 @@ extern "C" { #include #include #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); diff --git a/applications/main/bad_usb/helpers/ducky_script_keycodes.c b/applications/main/bad_usb/helpers/ducky_script_keycodes.c index 56b5144d4..290618c13 100644 --- a/applications/main/bad_usb/helpers/ducky_script_keycodes.c +++ b/applications/main/bad_usb/helpers/ducky_script_keycodes.c @@ -1,5 +1,4 @@ #include -#include #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; +} diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config.c b/applications/main/bad_usb/scenes/bad_usb_scene_config.c index 5477c5e80..d5f6fce23 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_config.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_config.c @@ -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; - view_dispatcher_send_custom_event(bad_usb->view_dispatcher, index); + 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); } diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c b/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c index 5d70b801b..2dbacbe12 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_config_layout.c @@ -1,6 +1,5 @@ #include "../bad_usb_app_i.h" #include "furi_hal_power.h" -#include "furi_hal_usb.h" #include static bool bad_usb_layout_select(BadUsbApp* bad_usb) { diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c b/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c index d6f05a1ed..5e2c3f14b 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_file_select.c @@ -1,6 +1,5 @@ #include "../bad_usb_app_i.h" #include -#include #include 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); diff --git a/applications/main/bad_usb/scenes/bad_usb_scene_work.c b/applications/main/bad_usb/scenes/bad_usb_scene_work.c index ad33a124d..0a383f029 100644 --- a/applications/main/bad_usb/scenes/bad_usb_scene_work.c +++ b/applications/main/bad_usb/scenes/bad_usb_scene_work.c @@ -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); } diff --git a/applications/main/bad_usb/views/bad_usb_view.c b/applications/main/bad_usb/views/bad_usb_view.c index 6ffa0f3c6..728f84348 100644 --- a/applications/main/bad_usb/views/bad_usb_view.c +++ b/applications/main/bad_usb/views/bad_usb_view.c @@ -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, diff --git a/applications/main/bad_usb/views/bad_usb_view.h b/applications/main/bad_usb/views/bad_usb_view.h index ee58e7bd0..45f13d650 100644 --- a/applications/main/bad_usb/views/bad_usb_view.h +++ b/applications/main/bad_usb/views/bad_usb_view.h @@ -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); diff --git a/documentation/file_formats/BadUsbScriptFormat.md b/documentation/file_formats/BadUsbScriptFormat.md index cc919da09..1bac3c4aa 100644 --- a/documentation/file_formats/BadUsbScriptFormat.md +++ b/documentation/file_formats/BadUsbScriptFormat.md @@ -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. diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 880bfe754..e80417b8e 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -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 diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 1f30a1150..a4a6cb250 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -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 diff --git a/targets/f7/furi_hal/furi_hal_usb_hid.c b/targets/f7/furi_hal/furi_hal_usb_hid.c index f48c4a781..5d1a9c46e 100644 --- a/targets/f7/furi_hal/furi_hal_usb_hid.c +++ b/targets/f7/furi_hal/furi_hal_usb_hid.c @@ -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); diff --git a/targets/furi_hal_include/furi_hal_usb_hid.h b/targets/furi_hal_include/furi_hal_usb_hid.h index da851cabb..29994196f 100644 --- a/targets/furi_hal_include/furi_hal_usb_hid.h +++ b/targets/furi_hal_include/furi_hal_usb_hid.h @@ -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