[FL-3134] BadUSB: Script interpreter refactoring (#2485)
* Script command and character tables * Non-blocking stringdelay, docs update * altchar/altstring fix * Layout select UI fix * Remove debug print Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									445a1aa7b0
								
							
						
					
					
						commit
						0444a80f19
					
				| @ -2,7 +2,7 @@ | ||||
| 
 | ||||
| #include "bad_usb_app.h" | ||||
| #include "scenes/bad_usb_scene.h" | ||||
| #include "bad_usb_script.h" | ||||
| #include "helpers/ducky_script.h" | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <assets_icons.h> | ||||
|  | ||||
| @ -5,17 +5,13 @@ | ||||
| #include <lib/toolbox/args.h> | ||||
| #include <furi_hal_usb_hid.h> | ||||
| #include <storage/storage.h> | ||||
| #include "bad_usb_script.h" | ||||
| #include "mnemonic.h" | ||||
| #include "ducky_script.h" | ||||
| #include "ducky_script_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #define TAG "BadUSB" | ||||
| #define WORKER_TAG TAG "Worker" | ||||
| 
 | ||||
| #define SCRIPT_STATE_ERROR (-1) | ||||
| #define SCRIPT_STATE_END (-2) | ||||
| #define SCRIPT_STATE_NEXT_LINE (-3) | ||||
| 
 | ||||
| #define BADUSB_ASCII_TO_KEY(script, x) \ | ||||
|     (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE) | ||||
| 
 | ||||
| @ -26,87 +22,20 @@ typedef enum { | ||||
|     WorkerEvtDisconnect = (1 << 3), | ||||
| } WorkerEvtFlags; | ||||
| 
 | ||||
| typedef struct { | ||||
|     char* name; | ||||
|     uint16_t keycode; | ||||
| } DuckyKey; | ||||
| 
 | ||||
| static const DuckyKey ducky_keys[] = { | ||||
|     {"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT}, | ||||
|     {"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT}, | ||||
|     {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT}, | ||||
|     {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI}, | ||||
|     {"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT}, | ||||
|     {"GUI-CTRL", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL}, | ||||
| 
 | ||||
|     {"CTRL", KEY_MOD_LEFT_CTRL}, | ||||
|     {"CONTROL", KEY_MOD_LEFT_CTRL}, | ||||
|     {"SHIFT", KEY_MOD_LEFT_SHIFT}, | ||||
|     {"ALT", KEY_MOD_LEFT_ALT}, | ||||
|     {"GUI", KEY_MOD_LEFT_GUI}, | ||||
|     {"WINDOWS", KEY_MOD_LEFT_GUI}, | ||||
| 
 | ||||
|     {"DOWNARROW", HID_KEYBOARD_DOWN_ARROW}, | ||||
|     {"DOWN", HID_KEYBOARD_DOWN_ARROW}, | ||||
|     {"LEFTARROW", HID_KEYBOARD_LEFT_ARROW}, | ||||
|     {"LEFT", HID_KEYBOARD_LEFT_ARROW}, | ||||
|     {"RIGHTARROW", HID_KEYBOARD_RIGHT_ARROW}, | ||||
|     {"RIGHT", HID_KEYBOARD_RIGHT_ARROW}, | ||||
|     {"UPARROW", HID_KEYBOARD_UP_ARROW}, | ||||
|     {"UP", HID_KEYBOARD_UP_ARROW}, | ||||
| 
 | ||||
|     {"ENTER", HID_KEYBOARD_RETURN}, | ||||
|     {"BREAK", HID_KEYBOARD_PAUSE}, | ||||
|     {"PAUSE", HID_KEYBOARD_PAUSE}, | ||||
|     {"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK}, | ||||
|     {"DELETE", HID_KEYBOARD_DELETE_FORWARD}, | ||||
|     {"BACKSPACE", HID_KEYBOARD_DELETE}, | ||||
|     {"END", HID_KEYBOARD_END}, | ||||
|     {"ESC", HID_KEYBOARD_ESCAPE}, | ||||
|     {"ESCAPE", HID_KEYBOARD_ESCAPE}, | ||||
|     {"HOME", HID_KEYBOARD_HOME}, | ||||
|     {"INSERT", HID_KEYBOARD_INSERT}, | ||||
|     {"NUMLOCK", HID_KEYPAD_NUMLOCK}, | ||||
|     {"PAGEUP", HID_KEYBOARD_PAGE_UP}, | ||||
|     {"PAGEDOWN", HID_KEYBOARD_PAGE_DOWN}, | ||||
|     {"PRINTSCREEN", HID_KEYBOARD_PRINT_SCREEN}, | ||||
|     {"SCROLLLOCK", HID_KEYBOARD_SCROLL_LOCK}, | ||||
|     {"SPACE", HID_KEYBOARD_SPACEBAR}, | ||||
|     {"TAB", HID_KEYBOARD_TAB}, | ||||
|     {"MENU", HID_KEYBOARD_APPLICATION}, | ||||
|     {"APP", HID_KEYBOARD_APPLICATION}, | ||||
| 
 | ||||
|     {"F1", HID_KEYBOARD_F1}, | ||||
|     {"F2", HID_KEYBOARD_F2}, | ||||
|     {"F3", HID_KEYBOARD_F3}, | ||||
|     {"F4", HID_KEYBOARD_F4}, | ||||
|     {"F5", HID_KEYBOARD_F5}, | ||||
|     {"F6", HID_KEYBOARD_F6}, | ||||
|     {"F7", HID_KEYBOARD_F7}, | ||||
|     {"F8", HID_KEYBOARD_F8}, | ||||
|     {"F9", HID_KEYBOARD_F9}, | ||||
|     {"F10", HID_KEYBOARD_F10}, | ||||
|     {"F11", HID_KEYBOARD_F11}, | ||||
|     {"F12", HID_KEYBOARD_F12}, | ||||
| }; | ||||
| 
 | ||||
| static const char ducky_cmd_comment[] = {"REM"}; | ||||
| static const char ducky_cmd_id[] = {"ID"}; | ||||
| static const char ducky_cmd_delay[] = {"DELAY "}; | ||||
| static const char ducky_cmd_string[] = {"STRING "}; | ||||
| static const char ducky_cmd_stringln[] = {"STRINGLN "}; | ||||
| static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "}; | ||||
| static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "}; | ||||
| static const char ducky_cmd_stringdelay_1[] = {"STRINGDELAY "}; | ||||
| static const char ducky_cmd_stringdelay_2[] = {"STRING_DELAY "}; | ||||
| static const char ducky_cmd_repeat[] = {"REPEAT "}; | ||||
| static const char ducky_cmd_sysrq[] = {"SYSRQ "}; | ||||
| static const char ducky_cmd_hold[] = {"HOLD "}; | ||||
| static const char ducky_cmd_release[] = {"RELEASE "}; | ||||
| 
 | ||||
| static const char ducky_cmd_altchar[] = {"ALTCHAR "}; | ||||
| static const char ducky_cmd_altstr_1[] = {"ALTSTRING "}; | ||||
| static const char ducky_cmd_altstr_2[] = {"ALTCODE "}; | ||||
| static const uint8_t numpad_keys[10] = { | ||||
|     HID_KEYPAD_0, | ||||
|     HID_KEYPAD_1, | ||||
|     HID_KEYPAD_2, | ||||
|     HID_KEYPAD_3, | ||||
|     HID_KEYPAD_4, | ||||
|     HID_KEYPAD_5, | ||||
|     HID_KEYPAD_6, | ||||
|     HID_KEYPAD_7, | ||||
|     HID_KEYPAD_8, | ||||
|     HID_KEYPAD_9, | ||||
| }; | ||||
| 
 | ||||
| uint32_t ducky_get_command_len(const char* line) { | ||||
|     uint32_t len = strlen(line); | ||||
| @ -121,76 +50,150 @@ bool ducky_is_line_end(const char chr) { | ||||
| } | ||||
| 
 | ||||
| uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars) { | ||||
|     for(size_t i = 0; i < (sizeof(ducky_keys) / sizeof(ducky_keys[0])); i++) { | ||||
|         size_t key_cmd_len = strlen(ducky_keys[i].name); | ||||
|         if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && | ||||
|            (ducky_is_line_end(param[key_cmd_len]))) { | ||||
|             return ducky_keys[i].keycode; | ||||
|         } | ||||
|     uint16_t keycode = ducky_get_keycode_by_name(param); | ||||
|     if(keycode != HID_KEYBOARD_NONE) { | ||||
|         return keycode; | ||||
|     } | ||||
| 
 | ||||
|     if((accept_chars) && (strlen(param) > 0)) { | ||||
|         return (BADUSB_ASCII_TO_KEY(bad_usb, param[0]) & 0xFF); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int32_t | ||||
|     ducky_parse_line(BadUsbScript* bad_usb, FuriString* line, char* error, size_t error_len) { | ||||
| bool ducky_get_number(const char* param, uint32_t* val) { | ||||
|     uint32_t value = 0; | ||||
|     if(sscanf(param, "%lu", &value) == 1) { | ||||
|         *val = value; | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void ducky_numlock_on() { | ||||
|     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); | ||||
|     } | ||||
| } | ||||
| bool ducky_numpad_press(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); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool ducky_altchar(const char* charcode) { | ||||
|     uint8_t i = 0; | ||||
|     bool state = false; | ||||
| 
 | ||||
|     furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); | ||||
| 
 | ||||
|     while(!ducky_is_line_end(charcode[i])) { | ||||
|         state = ducky_numpad_press(charcode[i]); | ||||
|         if(state == false) break; | ||||
|         i++; | ||||
|     } | ||||
| 
 | ||||
|     furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT); | ||||
|     return state; | ||||
| } | ||||
| 
 | ||||
| bool ducky_altstring(const char* param) { | ||||
|     uint32_t i = 0; | ||||
|     bool state = false; | ||||
| 
 | ||||
|     while(param[i] != '\0') { | ||||
|         if((param[i] < ' ') || (param[i] > '~')) { | ||||
|             i++; | ||||
|             continue; // Skip non-printable chars
 | ||||
|         } | ||||
| 
 | ||||
|         char temp_str[4]; | ||||
|         snprintf(temp_str, 4, "%u", param[i]); | ||||
| 
 | ||||
|         state = ducky_altchar(temp_str); | ||||
|         if(state == false) break; | ||||
|         i++; | ||||
|     } | ||||
|     return state; | ||||
| } | ||||
| 
 | ||||
| int32_t ducky_error(BadUsbScript* bad_usb, const char* text, ...) { | ||||
|     va_list args; | ||||
|     va_start(args, text); | ||||
| 
 | ||||
|     vsnprintf(bad_usb->st.error, sizeof(bad_usb->st.error), text, args); | ||||
| 
 | ||||
|     va_end(args); | ||||
|     return SCRIPT_STATE_ERROR; | ||||
| } | ||||
| 
 | ||||
| bool ducky_string(BadUsbScript* bad_usb, const char* param) { | ||||
|     uint32_t i = 0; | ||||
| 
 | ||||
|     while(param[i] != '\0') { | ||||
|         if(param[i] != '\n') { | ||||
|             uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]); | ||||
|             if(keycode != HID_KEYBOARD_NONE) { | ||||
|                 furi_hal_hid_kb_press(keycode); | ||||
|                 furi_hal_hid_kb_release(keycode); | ||||
|             } | ||||
|         } else { | ||||
|             furi_hal_hid_kb_press(HID_KEYBOARD_RETURN); | ||||
|             furi_hal_hid_kb_release(HID_KEYBOARD_RETURN); | ||||
|         } | ||||
|         i++; | ||||
|     } | ||||
|     bad_usb->stringdelay = 0; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static bool ducky_string_next(BadUsbScript* bad_usb) { | ||||
|     if(bad_usb->string_print_pos >= furi_string_size(bad_usb->string_print)) { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     char print_char = furi_string_get_char(bad_usb->string_print, bad_usb->string_print_pos); | ||||
| 
 | ||||
|     if(print_char != '\n') { | ||||
|         uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, print_char); | ||||
|         if(keycode != HID_KEYBOARD_NONE) { | ||||
|             furi_hal_hid_kb_press(keycode); | ||||
|             furi_hal_hid_kb_release(keycode); | ||||
|         } | ||||
|     } else { | ||||
|         furi_hal_hid_kb_press(HID_KEYBOARD_RETURN); | ||||
|         furi_hal_hid_kb_release(HID_KEYBOARD_RETURN); | ||||
|     } | ||||
| 
 | ||||
|     bad_usb->string_print_pos++; | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| static int32_t ducky_parse_line(BadUsbScript* bad_usb, FuriString* line) { | ||||
|     uint32_t line_len = furi_string_size(line); | ||||
|     const char* line_tmp = furi_string_get_cstr(line); | ||||
|     const char* ducky_cmd_table[] = { | ||||
|         ducky_cmd_comment, | ||||
|         ducky_cmd_id, | ||||
|         ducky_cmd_delay, | ||||
|         ducky_cmd_string, | ||||
|         ducky_cmd_defdelay_1, | ||||
|         ducky_cmd_defdelay_2, | ||||
|         ducky_cmd_stringdelay_1, | ||||
|         ducky_cmd_stringdelay_2, | ||||
|         ducky_cmd_repeat, | ||||
|         ducky_cmd_sysrq, | ||||
|         ducky_cmd_altchar, | ||||
|         ducky_cmd_altstr_1, | ||||
|         ducky_cmd_altstr_2, | ||||
|         ducky_cmd_stringln, | ||||
|         ducky_cmd_hold, | ||||
|         ducky_cmd_release, | ||||
|         NULL}; | ||||
|     int32_t (*fnc_ptr[])(BadUsbScript*, FuriString*, const char*, char*, size_t) = { | ||||
|         &ducky_fnc_noop, | ||||
|         &ducky_fnc_noop, | ||||
|         &ducky_fnc_delay, | ||||
|         &ducky_fnc_string, | ||||
|         &ducky_fnc_defdelay, | ||||
|         &ducky_fnc_defdelay, | ||||
|         &ducky_fnc_strdelay, | ||||
|         &ducky_fnc_strdelay, | ||||
|         &ducky_fnc_repeat, | ||||
|         &ducky_fnc_sysrq, | ||||
|         &ducky_fnc_altchar, | ||||
|         &ducky_fnc_altstring, | ||||
|         &ducky_fnc_altstring, | ||||
|         &ducky_fnc_stringln, | ||||
|         &ducky_fnc_hold, | ||||
|         &ducky_fnc_release, | ||||
|         NULL}; | ||||
| 
 | ||||
|     if(line_len == 0) { | ||||
|         return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
 | ||||
|     } | ||||
|     FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp); | ||||
| 
 | ||||
|     // Ducky Lang Functions
 | ||||
|     for(size_t i = 0; ducky_cmd_table[i]; i++) { | ||||
|         if(strncmp(line_tmp, ducky_cmd_table[i], strlen(ducky_cmd_table[i])) == 0) | ||||
|             return ((fnc_ptr[i])(bad_usb, line, line_tmp, error, error_len)); | ||||
|     int32_t cmd_result = ducky_execute_cmd(bad_usb, line_tmp); | ||||
|     if(cmd_result != SCRIPT_STATE_CMD_UNKNOWN) { | ||||
|         return cmd_result; | ||||
|     } | ||||
| 
 | ||||
|     // Special keys + modifiers
 | ||||
|     uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false); | ||||
|     if(key == HID_KEYBOARD_NONE) { | ||||
|         if(error != NULL) { | ||||
|             snprintf(error, error_len, "No keycode defined for %s", line_tmp); | ||||
|         } | ||||
|         return SCRIPT_STATE_ERROR; | ||||
|         return ducky_error(bad_usb, "No keycode defined for %s", line_tmp); | ||||
|     } | ||||
|     if((key & 0xFF00) != 0) { | ||||
|         // It's a modifier key
 | ||||
| @ -199,7 +202,7 @@ static int32_t | ||||
|     } | ||||
|     furi_hal_hid_kb_press(key); | ||||
|     furi_hal_hid_kb_release(key); | ||||
|     return (0); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) { | ||||
| @ -277,8 +280,7 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil | ||||
| 
 | ||||
|     if(bad_usb->repeat_cnt > 0) { | ||||
|         bad_usb->repeat_cnt--; | ||||
|         delay_val = ducky_parse_line( | ||||
|             bad_usb, bad_usb->line_prev, bad_usb->st.error, sizeof(bad_usb->st.error)); | ||||
|         delay_val = ducky_parse_line(bad_usb, bad_usb->line_prev); | ||||
|         if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
 | ||||
|             return 0; | ||||
|         } else if(delay_val < 0) { // Script error
 | ||||
| @ -313,10 +315,11 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil | ||||
|                 bad_usb->buf_len = bad_usb->buf_len + bad_usb->buf_start - (i + 1); | ||||
|                 bad_usb->buf_start = i + 1; | ||||
|                 furi_string_trim(bad_usb->line); | ||||
|                 delay_val = ducky_parse_line( | ||||
|                     bad_usb, bad_usb->line, bad_usb->st.error, sizeof(bad_usb->st.error)); | ||||
|                 delay_val = ducky_parse_line(bad_usb, bad_usb->line); | ||||
|                 if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
 | ||||
|                     return 0; | ||||
|                 } else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
 | ||||
|                     return delay_val; | ||||
|                 } else if(delay_val < 0) { | ||||
|                     bad_usb->st.error_line = bad_usb->st.line_cur; | ||||
|                     FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur); | ||||
| @ -339,10 +342,11 @@ static void bad_usb_hid_state_callback(bool state, void* context) { | ||||
|     furi_assert(context); | ||||
|     BadUsbScript* bad_usb = context; | ||||
| 
 | ||||
|     if(state == true) | ||||
|     if(state == true) { | ||||
|         furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect); | ||||
|     else | ||||
|     } 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) { | ||||
| @ -368,6 +372,7 @@ static int32_t bad_usb_worker(void* context) { | ||||
|     File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); | ||||
|     bad_usb->line = furi_string_alloc(); | ||||
|     bad_usb->line_prev = furi_string_alloc(); | ||||
|     bad_usb->string_print = furi_string_alloc(); | ||||
| 
 | ||||
|     furi_hal_hid_set_state_callback(bad_usb_hid_state_callback, bad_usb); | ||||
| 
 | ||||
| @ -420,6 +425,7 @@ static int32_t bad_usb_worker(void* context) { | ||||
|                 bad_usb->defdelay = 0; | ||||
|                 bad_usb->stringdelay = 0; | ||||
|                 bad_usb->repeat_cnt = 0; | ||||
|                 bad_usb->key_hold_nb = 0; | ||||
|                 bad_usb->file_end = false; | ||||
|                 storage_file_seek(script_file, 0, true); | ||||
|                 worker_state = BadUsbStateRunning; | ||||
| @ -492,12 +498,17 @@ 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(); | ||||
|                 } 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(); | ||||
|                     continue; | ||||
|                 } else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays
 | ||||
|                     delay_val = bad_usb->defdelay; | ||||
|                     bad_usb->string_print_pos = 0; | ||||
|                     worker_state = BadUsbStateStringDelay; | ||||
|                 } else if(delay_val > 1000) { | ||||
|                     bad_usb->st.state = BadUsbStateDelay; // Show long delays
 | ||||
|                     bad_usb->st.delay_remain = delay_val / 1000; | ||||
| @ -505,7 +516,35 @@ static int32_t bad_usb_worker(void* context) { | ||||
|             } else { | ||||
|                 furi_check((flags & FuriFlagError) == 0); | ||||
|             } | ||||
|         } else if(worker_state == BadUsbStateStringDelay) { // State: print string with delays
 | ||||
|             uint32_t flags = furi_thread_flags_wait( | ||||
|                 WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, | ||||
|                 FuriFlagWaitAny, | ||||
|                 bad_usb->stringdelay); | ||||
| 
 | ||||
|             if(!(flags & FuriFlagError)) { | ||||
|                 if(flags & WorkerEvtEnd) { | ||||
|                     break; | ||||
|                 } else if(flags & WorkerEvtToggle) { | ||||
|                     worker_state = BadUsbStateIdle; // Stop executing script
 | ||||
|                     furi_hal_hid_kb_release_all(); | ||||
|                 } else if(flags & WorkerEvtDisconnect) { | ||||
|                     worker_state = BadUsbStateNotConnected; // USB disconnected
 | ||||
|                     furi_hal_hid_kb_release_all(); | ||||
|                 } | ||||
|                 bad_usb->st.state = worker_state; | ||||
|                 continue; | ||||
|             } else if( | ||||
|                 (flags == (unsigned)FuriFlagErrorTimeout) || | ||||
|                 (flags == (unsigned)FuriFlagErrorResource)) { | ||||
|                 bool string_end = ducky_string_next(bad_usb); | ||||
|                 if(string_end) { | ||||
|                     bad_usb->stringdelay = 0; | ||||
|                     worker_state = BadUsbStateRunning; | ||||
|                 } | ||||
|             } else { | ||||
|                 furi_check((flags & FuriFlagError) == 0); | ||||
|             } | ||||
|         } else if( | ||||
|             (worker_state == BadUsbStateFileError) || | ||||
|             (worker_state == BadUsbStateScriptError)) { // State: error
 | ||||
| @ -524,6 +563,7 @@ static int32_t bad_usb_worker(void* context) { | ||||
|     storage_file_free(script_file); | ||||
|     furi_string_free(bad_usb->line); | ||||
|     furi_string_free(bad_usb->line_prev); | ||||
|     furi_string_free(bad_usb->string_print); | ||||
| 
 | ||||
|     FURI_LOG_I(WORKER_TAG, "End"); | ||||
| 
 | ||||
| @ -7,8 +7,6 @@ extern "C" { | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| 
 | ||||
| #define FILE_BUFFER_LEN 16 | ||||
| 
 | ||||
| typedef enum { | ||||
|     BadUsbStateInit, | ||||
|     BadUsbStateNotConnected, | ||||
| @ -16,6 +14,7 @@ typedef enum { | ||||
|     BadUsbStateWillRun, | ||||
|     BadUsbStateRunning, | ||||
|     BadUsbStateDelay, | ||||
|     BadUsbStateStringDelay, | ||||
|     BadUsbStateDone, | ||||
|     BadUsbStateScriptError, | ||||
|     BadUsbStateFileError, | ||||
| @ -30,23 +29,7 @@ typedef struct { | ||||
|     char error[64]; | ||||
| } BadUsbState; | ||||
| 
 | ||||
| typedef struct BadUsbScript { | ||||
|     FuriHalUsbHidConfig hid_cfg; | ||||
|     BadUsbState st; | ||||
|     FuriString* file_path; | ||||
|     uint32_t defdelay; | ||||
|     uint16_t layout[128]; | ||||
|     uint32_t stringdelay; | ||||
|     FuriThread* thread; | ||||
|     uint8_t file_buf[FILE_BUFFER_LEN + 1]; | ||||
|     uint8_t buf_start; | ||||
|     uint8_t buf_len; | ||||
|     bool file_end; | ||||
|     FuriString* line; | ||||
| 
 | ||||
|     FuriString* line_prev; | ||||
|     uint32_t repeat_cnt; | ||||
| } BadUsbScript; | ||||
| typedef struct BadUsbScript BadUsbScript; | ||||
| 
 | ||||
| BadUsbScript* bad_usb_script_open(FuriString* file_path); | ||||
| 
 | ||||
| @ -62,12 +45,6 @@ void bad_usb_script_toggle(BadUsbScript* bad_usb); | ||||
| 
 | ||||
| BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb); | ||||
| 
 | ||||
| uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars); | ||||
| 
 | ||||
| uint32_t ducky_get_command_len(const char* line); | ||||
| 
 | ||||
| bool ducky_is_line_end(const char chr); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										177
									
								
								applications/main/bad_usb/helpers/ducky_script_commands.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								applications/main/bad_usb/helpers/ducky_script_commands.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,177 @@ | ||||
| #include <furi_hal.h> | ||||
| #include <furi_hal_usb_hid.h> | ||||
| #include "ducky_script.h" | ||||
| #include "ducky_script_i.h" | ||||
| 
 | ||||
| typedef int32_t (*DuckyCmdCallback)(BadUsbScript* bad_usb, const char* line, int32_t param); | ||||
| 
 | ||||
| typedef struct { | ||||
|     char* name; | ||||
|     DuckyCmdCallback callback; | ||||
|     int32_t param; | ||||
| } DuckyCmd; | ||||
| 
 | ||||
| static int32_t ducky_fnc_delay(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||
|     UNUSED(param); | ||||
| 
 | ||||
|     line = &line[ducky_get_command_len(line) + 1]; | ||||
|     uint32_t delay_val = 0; | ||||
|     bool state = ducky_get_number(line, &delay_val); | ||||
|     if((state) && (delay_val > 0)) { | ||||
|         return (int32_t)delay_val; | ||||
|     } | ||||
| 
 | ||||
|     return ducky_error(bad_usb, "Invalid number %s", line); | ||||
| } | ||||
| 
 | ||||
| static int32_t ducky_fnc_defdelay(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||
|     UNUSED(param); | ||||
| 
 | ||||
|     line = &line[ducky_get_command_len(line) + 1]; | ||||
|     bool state = ducky_get_number(line, &bad_usb->defdelay); | ||||
|     if(!state) { | ||||
|         return ducky_error(bad_usb, "Invalid number %s", line); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int32_t ducky_fnc_strdelay(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||
|     UNUSED(param); | ||||
| 
 | ||||
|     line = &line[ducky_get_command_len(line) + 1]; | ||||
|     bool state = ducky_get_number(line, &bad_usb->stringdelay); | ||||
|     if(!state) { | ||||
|         return ducky_error(bad_usb, "Invalid number %s", line); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int32_t ducky_fnc_string(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||
|     line = &line[ducky_get_command_len(line) + 1]; | ||||
|     furi_string_set_str(bad_usb->string_print, line); | ||||
|     if(param == 1) { | ||||
|         furi_string_cat(bad_usb->string_print, "\n"); | ||||
|     } | ||||
| 
 | ||||
|     if(bad_usb->stringdelay == 0) { // stringdelay not set - run command immidiately
 | ||||
|         bool state = ducky_string(bad_usb, furi_string_get_cstr(bad_usb->string_print)); | ||||
|         if(!state) { | ||||
|             return ducky_error(bad_usb, "Invalid string %s", line); | ||||
|         } | ||||
|     } else { // stringdelay is set - run command in thread to keep handling external events
 | ||||
|         return SCRIPT_STATE_STRING_START; | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int32_t ducky_fnc_repeat(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||
|     UNUSED(param); | ||||
| 
 | ||||
|     line = &line[ducky_get_command_len(line) + 1]; | ||||
|     bool state = ducky_get_number(line, &bad_usb->repeat_cnt); | ||||
|     if((!state) || (bad_usb->repeat_cnt == 0)) { | ||||
|         return ducky_error(bad_usb, "Invalid number %s", line); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int32_t ducky_fnc_sysrq(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); | ||||
|     furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); | ||||
|     furi_hal_hid_kb_press(key); | ||||
|     furi_hal_hid_kb_release_all(); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int32_t ducky_fnc_altchar(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||
|     UNUSED(param); | ||||
| 
 | ||||
|     line = &line[ducky_get_command_len(line) + 1]; | ||||
|     ducky_numlock_on(); | ||||
|     bool state = ducky_altchar(line); | ||||
|     if(!state) { | ||||
|         return ducky_error(bad_usb, "Invalid altchar %s", line); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int32_t ducky_fnc_altstring(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||
|     UNUSED(param); | ||||
| 
 | ||||
|     line = &line[ducky_get_command_len(line) + 1]; | ||||
|     ducky_numlock_on(); | ||||
|     bool state = ducky_altstring(line); | ||||
|     if(!state) { | ||||
|         return ducky_error(bad_usb, "Invalid altstring %s", line); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int32_t ducky_fnc_hold(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||
|     UNUSED(param); | ||||
| 
 | ||||
|     line = &line[ducky_get_command_len(line) + 1]; | ||||
|     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->key_hold_nb++; | ||||
|     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); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int32_t ducky_fnc_release(BadUsbScript* bad_usb, const char* line, int32_t param) { | ||||
|     UNUSED(param); | ||||
| 
 | ||||
|     line = &line[ducky_get_command_len(line) + 1]; | ||||
|     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); | ||||
|     } | ||||
|     if(bad_usb->key_hold_nb == 0) { | ||||
|         return ducky_error(bad_usb, "No keys are hold"); | ||||
|     } | ||||
|     bad_usb->key_hold_nb--; | ||||
|     furi_hal_hid_kb_release(key); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static const DuckyCmd ducky_commands[] = { | ||||
|     {"REM ", NULL, -1}, | ||||
|     {"ID ", NULL, -1}, | ||||
|     {"DELAY ", ducky_fnc_delay, -1}, | ||||
|     {"STRING ", ducky_fnc_string, 0}, | ||||
|     {"STRINGLN ", ducky_fnc_string, 1}, | ||||
|     {"DEFAULT_DELAY ", ducky_fnc_defdelay, -1}, | ||||
|     {"DEFAULTDELAY ", ducky_fnc_defdelay, -1}, | ||||
|     {"STRINGDELAY ", ducky_fnc_strdelay, -1}, | ||||
|     {"STRING_DELAY ", ducky_fnc_strdelay, -1}, | ||||
|     {"REPEAT ", ducky_fnc_repeat, -1}, | ||||
|     {"SYSRQ ", ducky_fnc_sysrq, -1}, | ||||
|     {"ALTCHAR ", ducky_fnc_altchar, -1}, | ||||
|     {"ALTSTRING ", ducky_fnc_altstring, -1}, | ||||
|     {"ALTCODE ", ducky_fnc_altstring, -1}, | ||||
|     {"HOLD ", ducky_fnc_hold, -1}, | ||||
|     {"RELEASE ", ducky_fnc_release, -1}, | ||||
| }; | ||||
| 
 | ||||
| int32_t ducky_execute_cmd(BadUsbScript* bad_usb, const char* line) { | ||||
|     for(size_t i = 0; i < COUNT_OF(ducky_commands); i++) { | ||||
|         if(strncmp(line, ducky_commands[i].name, strlen(ducky_commands[i].name)) == 0) { | ||||
|             if(ducky_commands[i].callback == NULL) { | ||||
|                 return 0; | ||||
|             } else { | ||||
|                 return ((ducky_commands[i].callback)(bad_usb, line, ducky_commands[i].param)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return SCRIPT_STATE_CMD_UNKNOWN; | ||||
| } | ||||
							
								
								
									
										69
									
								
								applications/main/bad_usb/helpers/ducky_script_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								applications/main/bad_usb/helpers/ducky_script_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| #include "ducky_script.h" | ||||
| 
 | ||||
| #define SCRIPT_STATE_ERROR (-1) | ||||
| #define SCRIPT_STATE_END (-2) | ||||
| #define SCRIPT_STATE_NEXT_LINE (-3) | ||||
| #define SCRIPT_STATE_CMD_UNKNOWN (-4) | ||||
| #define SCRIPT_STATE_STRING_START (-5) | ||||
| 
 | ||||
| #define FILE_BUFFER_LEN 16 | ||||
| 
 | ||||
| struct BadUsbScript { | ||||
|     FuriHalUsbHidConfig hid_cfg; | ||||
|     FuriThread* thread; | ||||
|     BadUsbState st; | ||||
| 
 | ||||
|     FuriString* file_path; | ||||
|     uint8_t file_buf[FILE_BUFFER_LEN + 1]; | ||||
|     uint8_t buf_start; | ||||
|     uint8_t buf_len; | ||||
|     bool file_end; | ||||
| 
 | ||||
|     uint32_t defdelay; | ||||
|     uint32_t stringdelay; | ||||
|     uint16_t layout[128]; | ||||
| 
 | ||||
|     FuriString* line; | ||||
|     FuriString* line_prev; | ||||
|     uint32_t repeat_cnt; | ||||
|     uint8_t key_hold_nb; | ||||
| 
 | ||||
|     FuriString* string_print; | ||||
|     size_t string_print_pos; | ||||
| }; | ||||
| 
 | ||||
| uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars); | ||||
| 
 | ||||
| uint32_t ducky_get_command_len(const char* line); | ||||
| 
 | ||||
| bool ducky_is_line_end(const char chr); | ||||
| 
 | ||||
| uint16_t ducky_get_keycode_by_name(const char* param); | ||||
| 
 | ||||
| bool ducky_get_number(const char* param, uint32_t* val); | ||||
| 
 | ||||
| void ducky_numlock_on(void); | ||||
| 
 | ||||
| bool ducky_numpad_press(const char num); | ||||
| 
 | ||||
| bool ducky_altchar(const char* charcode); | ||||
| 
 | ||||
| bool ducky_altstring(const char* param); | ||||
| 
 | ||||
| bool ducky_string(BadUsbScript* bad_usb, const char* param); | ||||
| 
 | ||||
| int32_t ducky_execute_cmd(BadUsbScript* bad_usb, const char* line); | ||||
| 
 | ||||
| int32_t ducky_error(BadUsbScript* bad_usb, const char* text, ...); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										79
									
								
								applications/main/bad_usb/helpers/ducky_script_keycodes.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								applications/main/bad_usb/helpers/ducky_script_keycodes.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | ||||
| #include <furi_hal.h> | ||||
| #include <furi_hal_usb_hid.h> | ||||
| #include "ducky_script_i.h" | ||||
| 
 | ||||
| typedef struct { | ||||
|     char* name; | ||||
|     uint16_t keycode; | ||||
| } DuckyKey; | ||||
| 
 | ||||
| static const DuckyKey ducky_keys[] = { | ||||
|     {"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT}, | ||||
|     {"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT}, | ||||
|     {"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT}, | ||||
|     {"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI}, | ||||
|     {"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT}, | ||||
|     {"GUI-CTRL", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL}, | ||||
| 
 | ||||
|     {"CTRL", KEY_MOD_LEFT_CTRL}, | ||||
|     {"CONTROL", KEY_MOD_LEFT_CTRL}, | ||||
|     {"SHIFT", KEY_MOD_LEFT_SHIFT}, | ||||
|     {"ALT", KEY_MOD_LEFT_ALT}, | ||||
|     {"GUI", KEY_MOD_LEFT_GUI}, | ||||
|     {"WINDOWS", KEY_MOD_LEFT_GUI}, | ||||
| 
 | ||||
|     {"DOWNARROW", HID_KEYBOARD_DOWN_ARROW}, | ||||
|     {"DOWN", HID_KEYBOARD_DOWN_ARROW}, | ||||
|     {"LEFTARROW", HID_KEYBOARD_LEFT_ARROW}, | ||||
|     {"LEFT", HID_KEYBOARD_LEFT_ARROW}, | ||||
|     {"RIGHTARROW", HID_KEYBOARD_RIGHT_ARROW}, | ||||
|     {"RIGHT", HID_KEYBOARD_RIGHT_ARROW}, | ||||
|     {"UPARROW", HID_KEYBOARD_UP_ARROW}, | ||||
|     {"UP", HID_KEYBOARD_UP_ARROW}, | ||||
| 
 | ||||
|     {"ENTER", HID_KEYBOARD_RETURN}, | ||||
|     {"BREAK", HID_KEYBOARD_PAUSE}, | ||||
|     {"PAUSE", HID_KEYBOARD_PAUSE}, | ||||
|     {"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK}, | ||||
|     {"DELETE", HID_KEYBOARD_DELETE_FORWARD}, | ||||
|     {"BACKSPACE", HID_KEYBOARD_DELETE}, | ||||
|     {"END", HID_KEYBOARD_END}, | ||||
|     {"ESC", HID_KEYBOARD_ESCAPE}, | ||||
|     {"ESCAPE", HID_KEYBOARD_ESCAPE}, | ||||
|     {"HOME", HID_KEYBOARD_HOME}, | ||||
|     {"INSERT", HID_KEYBOARD_INSERT}, | ||||
|     {"NUMLOCK", HID_KEYPAD_NUMLOCK}, | ||||
|     {"PAGEUP", HID_KEYBOARD_PAGE_UP}, | ||||
|     {"PAGEDOWN", HID_KEYBOARD_PAGE_DOWN}, | ||||
|     {"PRINTSCREEN", HID_KEYBOARD_PRINT_SCREEN}, | ||||
|     {"SCROLLLOCK", HID_KEYBOARD_SCROLL_LOCK}, | ||||
|     {"SPACE", HID_KEYBOARD_SPACEBAR}, | ||||
|     {"TAB", HID_KEYBOARD_TAB}, | ||||
|     {"MENU", HID_KEYBOARD_APPLICATION}, | ||||
|     {"APP", HID_KEYBOARD_APPLICATION}, | ||||
| 
 | ||||
|     {"F1", HID_KEYBOARD_F1}, | ||||
|     {"F2", HID_KEYBOARD_F2}, | ||||
|     {"F3", HID_KEYBOARD_F3}, | ||||
|     {"F4", HID_KEYBOARD_F4}, | ||||
|     {"F5", HID_KEYBOARD_F5}, | ||||
|     {"F6", HID_KEYBOARD_F6}, | ||||
|     {"F7", HID_KEYBOARD_F7}, | ||||
|     {"F8", HID_KEYBOARD_F8}, | ||||
|     {"F9", HID_KEYBOARD_F9}, | ||||
|     {"F10", HID_KEYBOARD_F10}, | ||||
|     {"F11", HID_KEYBOARD_F11}, | ||||
|     {"F12", HID_KEYBOARD_F12}, | ||||
| }; | ||||
| 
 | ||||
| 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); | ||||
|         if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) && | ||||
|            (ducky_is_line_end(param[key_cmd_len]))) { | ||||
|             return ducky_keys[i].keycode; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return HID_KEYBOARD_NONE; | ||||
| } | ||||
| @ -1,327 +0,0 @@ | ||||
| #include <furi_hal.h> | ||||
| #include <furi_hal_usb_hid.h> | ||||
| #include "mnemonic.h" | ||||
| 
 | ||||
| #define TAG "BadUSB" | ||||
| #define WORKER_TAG TAG "Worker" | ||||
| 
 | ||||
| #define FILE_BUFFER_LEN 16 | ||||
| #define SCRIPT_STATE_ERROR (-1) | ||||
| #define SCRIPT_STATE_END (-2) | ||||
| #define SCRIPT_STATE_NEXT_LINE (-3) | ||||
| 
 | ||||
| #define BADUSB_ASCII_TO_KEY(script, x) \ | ||||
|     (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE) | ||||
| 
 | ||||
| static const uint8_t numpad_keys[10] = { | ||||
|     HID_KEYPAD_0, | ||||
|     HID_KEYPAD_1, | ||||
|     HID_KEYPAD_2, | ||||
|     HID_KEYPAD_3, | ||||
|     HID_KEYPAD_4, | ||||
|     HID_KEYPAD_5, | ||||
|     HID_KEYPAD_6, | ||||
|     HID_KEYPAD_7, | ||||
|     HID_KEYPAD_8, | ||||
|     HID_KEYPAD_9, | ||||
| }; | ||||
| 
 | ||||
| static bool ducky_get_number(const char* param, uint32_t* val) { | ||||
|     uint32_t value = 0; | ||||
|     if(sscanf(param, "%lu", &value) == 1) { | ||||
|         *val = value; | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| static void ducky_numlock_on() { | ||||
|     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); | ||||
|     } | ||||
| } | ||||
| static bool ducky_numpad_press(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); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static bool ducky_altchar(const char* charcode) { | ||||
|     uint8_t i = 0; | ||||
|     bool state = false; | ||||
| 
 | ||||
|     FURI_LOG_I(WORKER_TAG, "char %s", charcode); | ||||
| 
 | ||||
|     furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT); | ||||
| 
 | ||||
|     while(!ducky_is_line_end(charcode[i])) { | ||||
|         state = ducky_numpad_press(charcode[i]); | ||||
|         if(state == false) break; | ||||
|         i++; | ||||
|     } | ||||
| 
 | ||||
|     furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT); | ||||
|     return state; | ||||
| } | ||||
| 
 | ||||
| static bool ducky_altstring(const char* param) { | ||||
|     uint32_t i = 0; | ||||
|     bool state = false; | ||||
| 
 | ||||
|     while(param[i] != '\0') { | ||||
|         if((param[i] < ' ') || (param[i] > '~')) { | ||||
|             i++; | ||||
|             continue; // Skip non-printable chars
 | ||||
|         } | ||||
| 
 | ||||
|         char temp_str[4]; | ||||
|         snprintf(temp_str, 4, "%u", param[i]); | ||||
| 
 | ||||
|         state = ducky_altchar(temp_str); | ||||
|         if(state == false) break; | ||||
|         i++; | ||||
|     } | ||||
|     return state; | ||||
| } | ||||
| 
 | ||||
| static bool ducky_string(BadUsbScript* bad_usb, const char* param) { | ||||
|     uint32_t i = 0; | ||||
| 
 | ||||
|     while(param[i] != '\0') { | ||||
|         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); | ||||
|             if(bad_usb->stringdelay > 0) { | ||||
|                 furi_delay_ms(bad_usb->stringdelay); | ||||
|             } | ||||
|         } | ||||
|         i++; | ||||
|     } | ||||
|     bad_usb->stringdelay = 0; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| int32_t ducky_fnc_noop( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len) { | ||||
|     (void)bad_usb; | ||||
|     (void)line; | ||||
|     (void)line_tmp; | ||||
|     (void)error; | ||||
|     (void)error_len; | ||||
|     return (0); | ||||
| } | ||||
| 
 | ||||
| int32_t ducky_fnc_delay( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len) { | ||||
|     bool state = false; | ||||
|     (void)bad_usb; | ||||
|     (void)line; | ||||
| 
 | ||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|     uint32_t delay_val = 0; | ||||
|     state = ducky_get_number(line_tmp, &delay_val); | ||||
|     if((state) && (delay_val > 0)) { | ||||
|         return (int32_t)delay_val; | ||||
|     } | ||||
|     if(error != NULL) { | ||||
|         snprintf(error, error_len, "Invalid number %s", line_tmp); | ||||
|     } | ||||
|     return SCRIPT_STATE_ERROR; | ||||
| } | ||||
| 
 | ||||
| int32_t ducky_fnc_defdelay( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len) { | ||||
|     bool state = false; | ||||
|     (void)line; | ||||
| 
 | ||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|     state = ducky_get_number(line_tmp, &bad_usb->defdelay); | ||||
|     if(!state && error != NULL) { | ||||
|         snprintf(error, error_len, "Invalid number %s", line_tmp); | ||||
|     } | ||||
|     return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||
| } | ||||
| 
 | ||||
| int32_t ducky_fnc_strdelay( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len) { | ||||
|     bool state = false; | ||||
|     (void)line; | ||||
| 
 | ||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|     state = ducky_get_number(line_tmp, &bad_usb->stringdelay); | ||||
|     if((state) && (bad_usb->stringdelay > 0)) { | ||||
|         return state; | ||||
|     } | ||||
|     if(error != NULL) { | ||||
|         snprintf(error, error_len, "Invalid number %s", line_tmp); | ||||
|     } | ||||
|     return SCRIPT_STATE_ERROR; | ||||
| } | ||||
| 
 | ||||
| int32_t ducky_fnc_string( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len) { | ||||
|     bool state = false; | ||||
|     (void)line; | ||||
| 
 | ||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|     state = ducky_string(bad_usb, line_tmp); | ||||
|     if(!state && error != NULL) { | ||||
|         snprintf(error, error_len, "Invalid string %s", line_tmp); | ||||
|     } | ||||
|     return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||
| } | ||||
| 
 | ||||
| int32_t ducky_fnc_repeat( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len) { | ||||
|     bool state = false; | ||||
|     (void)line; | ||||
| 
 | ||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|     state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt); | ||||
|     if(!state && error != NULL) { | ||||
|         snprintf(error, error_len, "Invalid number %s", line_tmp); | ||||
|     } | ||||
|     return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||
| } | ||||
| 
 | ||||
| int32_t ducky_fnc_sysrq( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len) { | ||||
|     (void)error; | ||||
|     (void)error_len; | ||||
|     (void)line; | ||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|     uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true); | ||||
|     furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); | ||||
|     furi_hal_hid_kb_press(key); | ||||
|     furi_hal_hid_kb_release_all(); | ||||
|     return (0); | ||||
| } | ||||
| 
 | ||||
| int32_t ducky_fnc_altchar( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len) { | ||||
|     bool state = false; | ||||
|     (void)bad_usb; | ||||
|     (void)line; | ||||
| 
 | ||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|     ducky_numlock_on(); | ||||
|     state = ducky_altchar(line_tmp); | ||||
|     if(!state && error != NULL) { | ||||
|         snprintf(error, error_len, "Invalid altchar %s", line_tmp); | ||||
|     } | ||||
|     return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||
| } | ||||
| 
 | ||||
| int32_t ducky_fnc_altstring( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len) { | ||||
|     bool state = false; | ||||
|     (void)bad_usb; | ||||
|     (void)line; | ||||
| 
 | ||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|     ducky_numlock_on(); | ||||
|     state = ducky_altstring(line_tmp); | ||||
|     if(!state && error != NULL) { | ||||
|         snprintf(error, error_len, "Invalid altstring %s", line_tmp); | ||||
|     } | ||||
|     return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||
| } | ||||
| 
 | ||||
| int32_t ducky_fnc_stringln( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len) { | ||||
|     bool state = false; | ||||
|     (void)line; | ||||
| 
 | ||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|     state = ducky_string(bad_usb, line_tmp); | ||||
|     if(!state && error != NULL) { | ||||
|         snprintf(error, error_len, "Invalid string %s", line_tmp); | ||||
|     } | ||||
|     furi_hal_hid_kb_press(HID_KEYBOARD_RETURN); | ||||
|     furi_hal_hid_kb_release(HID_KEYBOARD_RETURN); | ||||
|     return (state) ? (0) : SCRIPT_STATE_ERROR; | ||||
| } | ||||
| 
 | ||||
| int32_t ducky_fnc_hold( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len) { | ||||
|     (void)line; | ||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|     uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true); | ||||
|     if(key == HID_KEYBOARD_NONE) { | ||||
|         if(error != NULL) { | ||||
|             snprintf(error, error_len, "No keycode defined for %s", line_tmp); | ||||
|         } | ||||
|         return SCRIPT_STATE_ERROR; | ||||
|     } | ||||
|     furi_hal_hid_kb_press(key); | ||||
|     return (0); | ||||
| } | ||||
| 
 | ||||
| int32_t ducky_fnc_release( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len) { | ||||
|     (void)line; | ||||
|     line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; | ||||
|     uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true); | ||||
|     if(key == HID_KEYBOARD_NONE) { | ||||
|         if(error != NULL) { | ||||
|             snprintf(error, error_len, "No keycode defined for %s", line_tmp); | ||||
|         } | ||||
|         return SCRIPT_STATE_ERROR; | ||||
|     } | ||||
|     furi_hal_hid_kb_release(key); | ||||
|     return (0); | ||||
| } | ||||
| @ -1,96 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #include "bad_usb_script.h" | ||||
| 
 | ||||
| // A no opperation function
 | ||||
| int32_t ducky_fnc_noop( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len); | ||||
| // DELAY
 | ||||
| int32_t ducky_fnc_delay( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len); | ||||
| // DEFAULTDELAY
 | ||||
| int32_t ducky_fnc_defdelay( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len); | ||||
| // STRINGDELAY
 | ||||
| int32_t ducky_fnc_strdelay( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len); | ||||
| // STRING
 | ||||
| int32_t ducky_fnc_string( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len); | ||||
| // STRINGLN
 | ||||
| int32_t ducky_fnc_stringln( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len); | ||||
| // REPEAT
 | ||||
| int32_t ducky_fnc_repeat( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len); | ||||
| // SYSRQ
 | ||||
| int32_t ducky_fnc_sysrq( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len); | ||||
| // ALTCHAR
 | ||||
| int32_t ducky_fnc_altchar( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len); | ||||
| // ALTSTRING
 | ||||
| int32_t ducky_fnc_altstring( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len); | ||||
| // HOLD
 | ||||
| int32_t ducky_fnc_hold( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len); | ||||
| // RELEASE
 | ||||
| int32_t ducky_fnc_release( | ||||
|     BadUsbScript* bad_usb, | ||||
|     FuriString* line, | ||||
|     const char* line_tmp, | ||||
|     char* error, | ||||
|     size_t error_len); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -17,7 +17,7 @@ void bad_usb_scene_config_on_enter(void* context) { | ||||
| 
 | ||||
|     submenu_add_item( | ||||
|         submenu, | ||||
|         "Keyboard Layout", | ||||
|         "Keyboard Layout (global)", | ||||
|         SubmenuIndexKeyboardLayout, | ||||
|         bad_usb_scene_config_submenu_callback, | ||||
|         bad_usb); | ||||
|  | ||||
| @ -33,8 +33,10 @@ void bad_usb_scene_config_layout_on_enter(void* context) { | ||||
| 
 | ||||
|     if(bad_usb_layout_select(bad_usb)) { | ||||
|         bad_usb_script_set_keyboard_layout(bad_usb->bad_usb_script, bad_usb->keyboard_layout); | ||||
|         scene_manager_search_and_switch_to_previous_scene(bad_usb->scene_manager, BadUsbSceneWork); | ||||
|     } else { | ||||
|         scene_manager_previous_scene(bad_usb->scene_manager); | ||||
|     } | ||||
|     scene_manager_previous_scene(bad_usb->scene_manager); | ||||
| } | ||||
| 
 | ||||
| bool bad_usb_scene_config_layout_on_event(void* context, SceneManagerEvent event) { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| #include "../bad_usb_script.h" | ||||
| #include "../helpers/ducky_script.h" | ||||
| #include "../bad_usb_app_i.h" | ||||
| #include "../views/bad_usb_view.h" | ||||
| #include <furi_hal.h> | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #include "bad_usb_view.h" | ||||
| #include "../bad_usb_script.h" | ||||
| #include "../helpers/ducky_script.h" | ||||
| #include <toolbox/path.h> | ||||
| #include <gui/elements.h> | ||||
| #include <assets_icons.h> | ||||
| @ -79,7 +79,12 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) { | ||||
|         canvas_draw_str_aligned( | ||||
|             canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); | ||||
|         furi_string_reset(disp_str); | ||||
|         canvas_draw_str_aligned(canvas, 127, 56, AlignRight, AlignBottom, model->state.error); | ||||
| 
 | ||||
|         furi_string_set_str(disp_str, model->state.error); | ||||
|         elements_string_fit_width(canvas, disp_str, canvas_width(canvas)); | ||||
|         canvas_draw_str_aligned( | ||||
|             canvas, 127, 56, AlignRight, AlignBottom, furi_string_get_cstr(disp_str)); | ||||
|         furi_string_reset(disp_str); | ||||
|     } else if(model->state.state == BadUsbStateIdle) { | ||||
|         canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18); | ||||
|         canvas_set_font(canvas, FontBigNumbers); | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gui/view.h> | ||||
| #include "../bad_usb_script.h" | ||||
| #include "../helpers/ducky_script.h" | ||||
| 
 | ||||
| typedef struct BadUsb BadUsb; | ||||
| typedef void (*BadUsbButtonCallback)(InputKey key, void* context); | ||||
|  | ||||
| @ -98,7 +98,7 @@ static void submenu_view_draw_callback(Canvas* canvas, void* _model) { | ||||
| 
 | ||||
|             FuriString* disp_str; | ||||
|             disp_str = furi_string_alloc_set(SubmenuItemArray_cref(it)->label); | ||||
|             elements_string_fit_width(canvas, disp_str, item_width - 20); | ||||
|             elements_string_fit_width(canvas, disp_str, item_width - (6 * 2)); | ||||
| 
 | ||||
|             canvas_draw_str( | ||||
|                 canvas, | ||||
|  | ||||
| @ -11,18 +11,18 @@ BadUsb app can execute only text scrips from `.txt` files, no compilation is req | ||||
| ## Comment line | ||||
| 
 | ||||
| Just a single comment line. The interpreter will ignore all text after the REM command. | ||||
| |Command|Parameters|Notes| | ||||
| |-|-|-| | ||||
| |REM|Comment text|| | ||||
| | Command | Parameters   | Notes | | ||||
| | ------- | ------------ | ----- | | ||||
| | REM     | Comment text |       | | ||||
| 
 | ||||
| ## Delay | ||||
| 
 | ||||
| Pause script execution by a defined time. | ||||
| |Command|Parameters|Notes| | ||||
| |-|-|-| | ||||
| |DELAY|Delay value in ms|Single delay| | ||||
| |DEFAULT_DELAY|Delay value in ms|Add delay before every next command| | ||||
| |DEFAULTDELAY|Delay value in ms|Same as DEFAULT_DELAY| | ||||
| | Command       | Parameters        | Notes                               | | ||||
| | ------------- | ----------------- | ----------------------------------- | | ||||
| | DELAY         | Delay value in ms | Single delay                        | | ||||
| | DEFAULT_DELAY | Delay value in ms | Add delay before every next command | | ||||
| | DEFAULTDELAY  | Delay value in ms | Same as DEFAULT_DELAY               | | ||||
| 
 | ||||
| ## Special keys | ||||
| 
 | ||||
| @ -56,32 +56,42 @@ Pause script execution by a defined time. | ||||
| ## Modifier keys | ||||
| 
 | ||||
| Can be combined with a special key command or a single character. | ||||
| |Command|Notes| | ||||
| |-|-| | ||||
| |CONTROL / CTRL|| | ||||
| |SHIFT|| | ||||
| |ALT|| | ||||
| |WINDOWS / GUI|| | ||||
| |CTRL-ALT|CTRL+ALT| | ||||
| |CTRL-SHIFT|CTRL+SHIFT| | ||||
| |ALT-SHIFT|ALT+SHIFT| | ||||
| |ALT-GUI|ALT+WIN| | ||||
| |GUI-SHIFT|WIN+SHIFT| | ||||
| |GUI-CTRL|WIN+CTRL| | ||||
| | Command        | Notes      | | ||||
| | -------------- | ---------- | | ||||
| | CONTROL / CTRL |            | | ||||
| | SHIFT          |            | | ||||
| | ALT            |            | | ||||
| | WINDOWS / GUI  |            | | ||||
| | CTRL-ALT       | CTRL+ALT   | | ||||
| | CTRL-SHIFT     | CTRL+SHIFT | | ||||
| | ALT-SHIFT      | ALT+SHIFT  | | ||||
| | ALT-GUI        | ALT+WIN    | | ||||
| | GUI-SHIFT      | WIN+SHIFT  | | ||||
| | GUI-CTRL       | WIN+CTRL   | | ||||
| 
 | ||||
| ## Key hold and release | ||||
| 
 | ||||
| Up to 5 keys can be hold simultaneously. | ||||
| | Command | Parameters                      | Notes                                     | | ||||
| | ------- | ------------------------------- | ----------------------------------------- | | ||||
| | HOLD    | Special key or single character | Press and hold key untill RELEASE command | | ||||
| | RELEASE | Special key or single character | Release key                               | | ||||
| 
 | ||||
| 
 | ||||
| ## String | ||||
| 
 | ||||
| | Command | Parameters  | Notes             | | ||||
| | ------- | ----------- | ----------------- | | ||||
| | STRING  | Text string | Print text string | | ||||
| | Command  | Parameters  | Notes                                      | | ||||
| | -------  | ----------- | -----------------                          | | ||||
| | STRING   | Text string | Print text string                          | | ||||
| | STRINGLN | Text string | Print text string and press enter after it | | ||||
| 
 | ||||
| ## String delay | ||||
| 
 | ||||
| Delay between keypresses. | ||||
| |Command|Parameters|Notes| | ||||
| |-|-|-| | ||||
| |STRING_DELAY|Delay value in ms|Applied once to next appearing string| | ||||
| |STRINGDELAY|Delay value in ms|Same as STRING_DELAY| | ||||
| | Command      | Parameters        | Notes                                         | | ||||
| | ------------ | ----------------- | --------------------------------------------- | | ||||
| | STRING_DELAY | Delay value in ms | Applied once to next appearing STRING command | | ||||
| | STRINGDELAY  | Delay value in ms | Same as STRING_DELAY                          | | ||||
| 
 | ||||
| ## Repeat | ||||
| 
 | ||||
| @ -91,19 +101,19 @@ Delay between keypresses. | ||||
| 
 | ||||
| ## ALT+Numpad input | ||||
| 
 | ||||
| On Windows and some Linux systems, you can print characters by pressing `ALT` key and entering its code on Numpad. | ||||
| |Command|Parameters|Notes| | ||||
| |-|-|-| | ||||
| |ALTCHAR|Character code|Print single character| | ||||
| |ALTSTRING|Text string|Print text string using ALT+Numpad method| | ||||
| |ALTCODE|Text string|Same as ALTSTRING, presents in some Duckyscript implementations| | ||||
| On Windows and some Linux systems, you can print characters by holding `ALT` key and entering its code on Numpad. | ||||
| | Command   | Parameters     | Notes                                                           | | ||||
| | --------- | -------------- | --------------------------------------------------------------- | | ||||
| | ALTCHAR   | Character code | Print single character                                          | | ||||
| | ALTSTRING | Text string    | Print text string using ALT+Numpad method                       | | ||||
| | ALTCODE   | Text string    | Same as ALTSTRING, presents in some Duckyscript implementations | | ||||
| 
 | ||||
| ## SysRq | ||||
| 
 | ||||
| Send [SysRq command](https://en.wikipedia.org/wiki/Magic_SysRq_key) | ||||
| |Command|Parameters|Notes| | ||||
| |-|-|-| | ||||
| |SYSRQ|Single character|| | ||||
| | Command | Parameters       | Notes | | ||||
| | ------- | ---------------- | ----- | | ||||
| | SYSRQ   | Single character |       | | ||||
| 
 | ||||
| ## USB device ID | ||||
| 
 | ||||
|  | ||||
| @ -11,9 +11,6 @@ | ||||
| #define HID_EP_OUT 0x01 | ||||
| #define HID_EP_SZ 0x10 | ||||
| 
 | ||||
| #define HID_KB_MAX_KEYS 6 | ||||
| #define HID_CONSUMER_MAX_KEYS 2 | ||||
| 
 | ||||
| #define HID_INTERVAL 2 | ||||
| 
 | ||||
| #define HID_VID_DEFAULT 0x046D | ||||
|  | ||||
| @ -9,6 +9,11 @@ | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /** Max number of simultaneously pressed keys (keyboard) */ | ||||
| #define HID_KB_MAX_KEYS 6 | ||||
| /** Max number of simultaneously pressed keys (consumer control) */ | ||||
| #define HID_CONSUMER_MAX_KEYS 2 | ||||
| 
 | ||||
| #define HID_KEYBOARD_NONE 0x00 | ||||
| 
 | ||||
| /** HID keyboard modifier keys */ | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nikolay Minaylov
						Nikolay Minaylov