ducky_script.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include <gui/gui.h>
  4. #include <input/input.h>
  5. #include <lib/toolbox/args.h>
  6. #include <furi_hal_usb_hid.h>
  7. #include <storage/storage.h>
  8. #include "ducky_script.h"
  9. #include "ducky_script_i.h"
  10. #include <dolphin/dolphin.h>
  11. #define TAG "BadUSB"
  12. #define WORKER_TAG TAG "Worker"
  13. #define BADUSB_ASCII_TO_KEY(script, x) \
  14. (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE)
  15. typedef enum {
  16. WorkerEvtToggle = (1 << 0),
  17. WorkerEvtEnd = (1 << 1),
  18. WorkerEvtConnect = (1 << 2),
  19. WorkerEvtDisconnect = (1 << 3),
  20. } WorkerEvtFlags;
  21. static const char ducky_cmd_id[] = {"ID"};
  22. static const uint8_t numpad_keys[10] = {
  23. HID_KEYPAD_0,
  24. HID_KEYPAD_1,
  25. HID_KEYPAD_2,
  26. HID_KEYPAD_3,
  27. HID_KEYPAD_4,
  28. HID_KEYPAD_5,
  29. HID_KEYPAD_6,
  30. HID_KEYPAD_7,
  31. HID_KEYPAD_8,
  32. HID_KEYPAD_9,
  33. };
  34. uint32_t ducky_get_command_len(const char* line) {
  35. uint32_t len = strlen(line);
  36. for(uint32_t i = 0; i < len; i++) {
  37. if(line[i] == ' ') return i;
  38. }
  39. return 0;
  40. }
  41. bool ducky_is_line_end(const char chr) {
  42. return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n'));
  43. }
  44. uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars) {
  45. uint16_t keycode = ducky_get_keycode_by_name(param);
  46. if(keycode != HID_KEYBOARD_NONE) {
  47. return keycode;
  48. }
  49. if((accept_chars) && (strlen(param) > 0)) {
  50. return (BADUSB_ASCII_TO_KEY(bad_usb, param[0]) & 0xFF);
  51. }
  52. return 0;
  53. }
  54. bool ducky_get_number(const char* param, uint32_t* val) {
  55. uint32_t value = 0;
  56. if(sscanf(param, "%lu", &value) == 1) {
  57. *val = value;
  58. return true;
  59. }
  60. return false;
  61. }
  62. void ducky_numlock_on() {
  63. if((furi_hal_hid_get_led_state() & HID_KB_LED_NUM) == 0) {
  64. furi_hal_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK);
  65. furi_hal_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK);
  66. }
  67. }
  68. bool ducky_numpad_press(const char num) {
  69. if((num < '0') || (num > '9')) return false;
  70. uint16_t key = numpad_keys[num - '0'];
  71. furi_hal_hid_kb_press(key);
  72. furi_hal_hid_kb_release(key);
  73. return true;
  74. }
  75. bool ducky_altchar(const char* charcode) {
  76. uint8_t i = 0;
  77. bool state = false;
  78. furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT);
  79. while(!ducky_is_line_end(charcode[i])) {
  80. state = ducky_numpad_press(charcode[i]);
  81. if(state == false) break;
  82. i++;
  83. }
  84. furi_hal_hid_kb_release(KEY_MOD_LEFT_ALT);
  85. return state;
  86. }
  87. bool ducky_altstring(const char* param) {
  88. uint32_t i = 0;
  89. bool state = false;
  90. while(param[i] != '\0') {
  91. if((param[i] < ' ') || (param[i] > '~')) {
  92. i++;
  93. continue; // Skip non-printable chars
  94. }
  95. char temp_str[4];
  96. snprintf(temp_str, 4, "%u", param[i]);
  97. state = ducky_altchar(temp_str);
  98. if(state == false) break;
  99. i++;
  100. }
  101. return state;
  102. }
  103. int32_t ducky_error(BadUsbScript* bad_usb, const char* text, ...) {
  104. va_list args;
  105. va_start(args, text);
  106. vsnprintf(bad_usb->st.error, sizeof(bad_usb->st.error), text, args);
  107. va_end(args);
  108. return SCRIPT_STATE_ERROR;
  109. }
  110. bool ducky_string(BadUsbScript* bad_usb, const char* param) {
  111. uint32_t i = 0;
  112. while(param[i] != '\0') {
  113. if(param[i] != '\n') {
  114. uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, param[i]);
  115. if(keycode != HID_KEYBOARD_NONE) {
  116. furi_hal_hid_kb_press(keycode);
  117. furi_hal_hid_kb_release(keycode);
  118. }
  119. } else {
  120. furi_hal_hid_kb_press(HID_KEYBOARD_RETURN);
  121. furi_hal_hid_kb_release(HID_KEYBOARD_RETURN);
  122. }
  123. i++;
  124. }
  125. bad_usb->stringdelay = 0;
  126. return true;
  127. }
  128. static bool ducky_string_next(BadUsbScript* bad_usb) {
  129. if(bad_usb->string_print_pos >= furi_string_size(bad_usb->string_print)) {
  130. return true;
  131. }
  132. char print_char = furi_string_get_char(bad_usb->string_print, bad_usb->string_print_pos);
  133. if(print_char != '\n') {
  134. uint16_t keycode = BADUSB_ASCII_TO_KEY(bad_usb, print_char);
  135. if(keycode != HID_KEYBOARD_NONE) {
  136. furi_hal_hid_kb_press(keycode);
  137. furi_hal_hid_kb_release(keycode);
  138. }
  139. } else {
  140. furi_hal_hid_kb_press(HID_KEYBOARD_RETURN);
  141. furi_hal_hid_kb_release(HID_KEYBOARD_RETURN);
  142. }
  143. bad_usb->string_print_pos++;
  144. return false;
  145. }
  146. static int32_t ducky_parse_line(BadUsbScript* bad_usb, FuriString* line) {
  147. uint32_t line_len = furi_string_size(line);
  148. const char* line_tmp = furi_string_get_cstr(line);
  149. if(line_len == 0) {
  150. return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
  151. }
  152. FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp);
  153. // Ducky Lang Functions
  154. int32_t cmd_result = ducky_execute_cmd(bad_usb, line_tmp);
  155. if(cmd_result != SCRIPT_STATE_CMD_UNKNOWN) {
  156. return cmd_result;
  157. }
  158. // Special keys + modifiers
  159. uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false);
  160. if(key == HID_KEYBOARD_NONE) {
  161. return ducky_error(bad_usb, "No keycode defined for %s", line_tmp);
  162. }
  163. if((key & 0xFF00) != 0) {
  164. // It's a modifier key
  165. line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
  166. key |= ducky_get_keycode(bad_usb, line_tmp, true);
  167. }
  168. furi_hal_hid_kb_press(key);
  169. furi_hal_hid_kb_release(key);
  170. return 0;
  171. }
  172. static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) {
  173. if(sscanf(line, "%lX:%lX", &bad_usb->hid_cfg.vid, &bad_usb->hid_cfg.pid) == 2) {
  174. bad_usb->hid_cfg.manuf[0] = '\0';
  175. bad_usb->hid_cfg.product[0] = '\0';
  176. uint8_t id_len = ducky_get_command_len(line);
  177. if(!ducky_is_line_end(line[id_len + 1])) {
  178. sscanf(
  179. &line[id_len + 1],
  180. "%31[^\r\n:]:%31[^\r\n]",
  181. bad_usb->hid_cfg.manuf,
  182. bad_usb->hid_cfg.product);
  183. }
  184. FURI_LOG_D(
  185. WORKER_TAG,
  186. "set id: %04lX:%04lX mfr:%s product:%s",
  187. bad_usb->hid_cfg.vid,
  188. bad_usb->hid_cfg.pid,
  189. bad_usb->hid_cfg.manuf,
  190. bad_usb->hid_cfg.product);
  191. return true;
  192. }
  193. return false;
  194. }
  195. static bool ducky_script_preload(BadUsbScript* bad_usb, File* script_file) {
  196. uint8_t ret = 0;
  197. uint32_t line_len = 0;
  198. furi_string_reset(bad_usb->line);
  199. do {
  200. ret = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN);
  201. for(uint16_t i = 0; i < ret; i++) {
  202. if(bad_usb->file_buf[i] == '\n' && line_len > 0) {
  203. bad_usb->st.line_nb++;
  204. line_len = 0;
  205. } else {
  206. if(bad_usb->st.line_nb == 0) { // Save first line
  207. furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]);
  208. }
  209. line_len++;
  210. }
  211. }
  212. if(storage_file_eof(script_file)) {
  213. if(line_len > 0) {
  214. bad_usb->st.line_nb++;
  215. break;
  216. }
  217. }
  218. } while(ret > 0);
  219. const char* line_tmp = furi_string_get_cstr(bad_usb->line);
  220. bool id_set = false; // Looking for ID command at first line
  221. if(strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0) {
  222. id_set = ducky_set_usb_id(bad_usb, &line_tmp[strlen(ducky_cmd_id) + 1]);
  223. }
  224. if(id_set) {
  225. furi_check(furi_hal_usb_set_config(&usb_hid, &bad_usb->hid_cfg));
  226. } else {
  227. furi_check(furi_hal_usb_set_config(&usb_hid, NULL));
  228. }
  229. storage_file_seek(script_file, 0, true);
  230. furi_string_reset(bad_usb->line);
  231. return true;
  232. }
  233. static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_file) {
  234. int32_t delay_val = 0;
  235. if(bad_usb->repeat_cnt > 0) {
  236. bad_usb->repeat_cnt--;
  237. delay_val = ducky_parse_line(bad_usb, bad_usb->line_prev);
  238. if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
  239. return 0;
  240. } else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
  241. return delay_val;
  242. } else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
  243. return delay_val;
  244. } else if(delay_val < 0) { // Script error
  245. bad_usb->st.error_line = bad_usb->st.line_cur - 1;
  246. FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur - 1U);
  247. return SCRIPT_STATE_ERROR;
  248. } else {
  249. return (delay_val + bad_usb->defdelay);
  250. }
  251. }
  252. furi_string_set(bad_usb->line_prev, bad_usb->line);
  253. furi_string_reset(bad_usb->line);
  254. while(1) {
  255. if(bad_usb->buf_len == 0) {
  256. bad_usb->buf_len = storage_file_read(script_file, bad_usb->file_buf, FILE_BUFFER_LEN);
  257. if(storage_file_eof(script_file)) {
  258. if((bad_usb->buf_len < FILE_BUFFER_LEN) && (bad_usb->file_end == false)) {
  259. bad_usb->file_buf[bad_usb->buf_len] = '\n';
  260. bad_usb->buf_len++;
  261. bad_usb->file_end = true;
  262. }
  263. }
  264. bad_usb->buf_start = 0;
  265. if(bad_usb->buf_len == 0) return SCRIPT_STATE_END;
  266. }
  267. for(uint8_t i = bad_usb->buf_start; i < (bad_usb->buf_start + bad_usb->buf_len); i++) {
  268. if(bad_usb->file_buf[i] == '\n' && furi_string_size(bad_usb->line) > 0) {
  269. bad_usb->st.line_cur++;
  270. bad_usb->buf_len = bad_usb->buf_len + bad_usb->buf_start - (i + 1);
  271. bad_usb->buf_start = i + 1;
  272. furi_string_trim(bad_usb->line);
  273. delay_val = ducky_parse_line(bad_usb, bad_usb->line);
  274. if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
  275. return 0;
  276. } else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
  277. return delay_val;
  278. } else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
  279. return delay_val;
  280. } else if(delay_val < 0) {
  281. bad_usb->st.error_line = bad_usb->st.line_cur;
  282. FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur);
  283. return SCRIPT_STATE_ERROR;
  284. } else {
  285. return (delay_val + bad_usb->defdelay);
  286. }
  287. } else {
  288. furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]);
  289. }
  290. }
  291. bad_usb->buf_len = 0;
  292. if(bad_usb->file_end) return SCRIPT_STATE_END;
  293. }
  294. return 0;
  295. }
  296. static void bad_usb_hid_state_callback(bool state, void* context) {
  297. furi_assert(context);
  298. BadUsbScript* bad_usb = context;
  299. if(state == true) {
  300. furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtConnect);
  301. } else {
  302. furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtDisconnect);
  303. }
  304. }
  305. static uint32_t bad_usb_flags_get(uint32_t flags_mask, uint32_t timeout) {
  306. uint32_t flags = furi_thread_flags_get();
  307. furi_check((flags & FuriFlagError) == 0);
  308. if(flags == 0) {
  309. flags = furi_thread_flags_wait(flags_mask, FuriFlagWaitAny, timeout);
  310. furi_check(((flags & FuriFlagError) == 0) || (flags == (unsigned)FuriFlagErrorTimeout));
  311. } else {
  312. uint32_t state = furi_thread_flags_clear(flags);
  313. furi_check((state & FuriFlagError) == 0);
  314. }
  315. return flags;
  316. }
  317. static int32_t bad_usb_worker(void* context) {
  318. BadUsbScript* bad_usb = context;
  319. BadUsbWorkerState worker_state = BadUsbStateInit;
  320. int32_t delay_val = 0;
  321. FURI_LOG_I(WORKER_TAG, "Init");
  322. File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
  323. bad_usb->line = furi_string_alloc();
  324. bad_usb->line_prev = furi_string_alloc();
  325. bad_usb->string_print = furi_string_alloc();
  326. furi_hal_hid_set_state_callback(bad_usb_hid_state_callback, bad_usb);
  327. while(1) {
  328. if(worker_state == BadUsbStateInit) { // State: initialization
  329. if(storage_file_open(
  330. script_file,
  331. furi_string_get_cstr(bad_usb->file_path),
  332. FSAM_READ,
  333. FSOM_OPEN_EXISTING)) {
  334. if((ducky_script_preload(bad_usb, script_file)) && (bad_usb->st.line_nb > 0)) {
  335. if(furi_hal_hid_is_connected()) {
  336. worker_state = BadUsbStateIdle; // Ready to run
  337. } else {
  338. worker_state = BadUsbStateNotConnected; // USB not connected
  339. }
  340. } else {
  341. worker_state = BadUsbStateScriptError; // Script preload error
  342. }
  343. } else {
  344. FURI_LOG_E(WORKER_TAG, "File open error");
  345. worker_state = BadUsbStateFileError; // File open error
  346. }
  347. bad_usb->st.state = worker_state;
  348. } else if(worker_state == BadUsbStateNotConnected) { // State: USB not connected
  349. uint32_t flags = bad_usb_flags_get(
  350. WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, FuriWaitForever);
  351. if(flags & WorkerEvtEnd) {
  352. break;
  353. } else if(flags & WorkerEvtConnect) {
  354. worker_state = BadUsbStateIdle; // Ready to run
  355. } else if(flags & WorkerEvtToggle) {
  356. worker_state = BadUsbStateWillRun; // Will run when USB is connected
  357. }
  358. bad_usb->st.state = worker_state;
  359. } else if(worker_state == BadUsbStateIdle) { // State: ready to start
  360. uint32_t flags = bad_usb_flags_get(
  361. WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriWaitForever);
  362. if(flags & WorkerEvtEnd) {
  363. break;
  364. } else if(flags & WorkerEvtToggle) { // Start executing script
  365. DOLPHIN_DEED(DolphinDeedBadUsbPlayScript);
  366. delay_val = 0;
  367. bad_usb->buf_len = 0;
  368. bad_usb->st.line_cur = 0;
  369. bad_usb->defdelay = 0;
  370. bad_usb->stringdelay = 0;
  371. bad_usb->repeat_cnt = 0;
  372. bad_usb->key_hold_nb = 0;
  373. bad_usb->file_end = false;
  374. storage_file_seek(script_file, 0, true);
  375. worker_state = BadUsbStateRunning;
  376. } else if(flags & WorkerEvtDisconnect) {
  377. worker_state = BadUsbStateNotConnected; // USB disconnected
  378. }
  379. bad_usb->st.state = worker_state;
  380. } else if(worker_state == BadUsbStateWillRun) { // State: start on connection
  381. uint32_t flags = bad_usb_flags_get(
  382. WorkerEvtEnd | WorkerEvtConnect | WorkerEvtToggle, FuriWaitForever);
  383. if(flags & WorkerEvtEnd) {
  384. break;
  385. } else if(flags & WorkerEvtConnect) { // Start executing script
  386. DOLPHIN_DEED(DolphinDeedBadUsbPlayScript);
  387. delay_val = 0;
  388. bad_usb->buf_len = 0;
  389. bad_usb->st.line_cur = 0;
  390. bad_usb->defdelay = 0;
  391. bad_usb->stringdelay = 0;
  392. bad_usb->repeat_cnt = 0;
  393. bad_usb->file_end = false;
  394. storage_file_seek(script_file, 0, true);
  395. // extra time for PC to recognize Flipper as keyboard
  396. flags = furi_thread_flags_wait(
  397. WorkerEvtEnd | WorkerEvtDisconnect | WorkerEvtToggle,
  398. FuriFlagWaitAny | FuriFlagNoClear,
  399. 1500);
  400. if(flags == (unsigned)FuriFlagErrorTimeout) {
  401. // If nothing happened - start script execution
  402. worker_state = BadUsbStateRunning;
  403. } else if(flags & WorkerEvtToggle) {
  404. worker_state = BadUsbStateIdle;
  405. furi_thread_flags_clear(WorkerEvtToggle);
  406. }
  407. } else if(flags & WorkerEvtToggle) { // Cancel scheduled execution
  408. worker_state = BadUsbStateNotConnected;
  409. }
  410. bad_usb->st.state = worker_state;
  411. } else if(worker_state == BadUsbStateRunning) { // State: running
  412. uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val);
  413. uint32_t flags = furi_thread_flags_wait(
  414. WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriFlagWaitAny, delay_cur);
  415. delay_val -= delay_cur;
  416. if(!(flags & FuriFlagError)) {
  417. if(flags & WorkerEvtEnd) {
  418. break;
  419. } else if(flags & WorkerEvtToggle) {
  420. worker_state = BadUsbStateIdle; // Stop executing script
  421. furi_hal_hid_kb_release_all();
  422. } else if(flags & WorkerEvtDisconnect) {
  423. worker_state = BadUsbStateNotConnected; // USB disconnected
  424. furi_hal_hid_kb_release_all();
  425. }
  426. bad_usb->st.state = worker_state;
  427. continue;
  428. } else if(
  429. (flags == (unsigned)FuriFlagErrorTimeout) ||
  430. (flags == (unsigned)FuriFlagErrorResource)) {
  431. if(delay_val > 0) {
  432. bad_usb->st.delay_remain--;
  433. continue;
  434. }
  435. bad_usb->st.state = BadUsbStateRunning;
  436. delay_val = ducky_script_execute_next(bad_usb, script_file);
  437. if(delay_val == SCRIPT_STATE_ERROR) { // Script error
  438. delay_val = 0;
  439. worker_state = BadUsbStateScriptError;
  440. bad_usb->st.state = worker_state;
  441. furi_hal_hid_kb_release_all();
  442. } else if(delay_val == SCRIPT_STATE_END) { // End of script
  443. delay_val = 0;
  444. worker_state = BadUsbStateIdle;
  445. bad_usb->st.state = BadUsbStateDone;
  446. furi_hal_hid_kb_release_all();
  447. continue;
  448. } else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays
  449. delay_val = bad_usb->defdelay;
  450. bad_usb->string_print_pos = 0;
  451. worker_state = BadUsbStateStringDelay;
  452. } else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // set state to wait for user input
  453. worker_state = BadUsbStateWaitForBtn;
  454. bad_usb->st.state = BadUsbStateWaitForBtn; // Show long delays
  455. } else if(delay_val > 1000) {
  456. bad_usb->st.state = BadUsbStateDelay; // Show long delays
  457. bad_usb->st.delay_remain = delay_val / 1000;
  458. }
  459. } else {
  460. furi_check((flags & FuriFlagError) == 0);
  461. }
  462. } else if(worker_state == BadUsbStateWaitForBtn) { // State: Wait for button Press
  463. uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val);
  464. uint32_t flags = furi_thread_flags_wait(
  465. WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect, FuriFlagWaitAny, delay_cur);
  466. if(!(flags & FuriFlagError)) {
  467. if(flags & WorkerEvtEnd) {
  468. break;
  469. } else if(flags & WorkerEvtToggle) {
  470. delay_val = 0;
  471. worker_state = BadUsbStateRunning;
  472. } else if(flags & WorkerEvtDisconnect) {
  473. worker_state = BadUsbStateNotConnected; // USB disconnected
  474. furi_hal_hid_kb_release_all();
  475. }
  476. bad_usb->st.state = worker_state;
  477. continue;
  478. }
  479. } else if(worker_state == BadUsbStateStringDelay) { // State: print string with delays
  480. uint32_t flags = furi_thread_flags_wait(
  481. WorkerEvtEnd | WorkerEvtToggle | WorkerEvtDisconnect,
  482. FuriFlagWaitAny,
  483. bad_usb->stringdelay);
  484. if(!(flags & FuriFlagError)) {
  485. if(flags & WorkerEvtEnd) {
  486. break;
  487. } else if(flags & WorkerEvtToggle) {
  488. worker_state = BadUsbStateIdle; // Stop executing script
  489. furi_hal_hid_kb_release_all();
  490. } else if(flags & WorkerEvtDisconnect) {
  491. worker_state = BadUsbStateNotConnected; // USB disconnected
  492. furi_hal_hid_kb_release_all();
  493. }
  494. bad_usb->st.state = worker_state;
  495. continue;
  496. } else if(
  497. (flags == (unsigned)FuriFlagErrorTimeout) ||
  498. (flags == (unsigned)FuriFlagErrorResource)) {
  499. bool string_end = ducky_string_next(bad_usb);
  500. if(string_end) {
  501. bad_usb->stringdelay = 0;
  502. worker_state = BadUsbStateRunning;
  503. }
  504. } else {
  505. furi_check((flags & FuriFlagError) == 0);
  506. }
  507. } else if(
  508. (worker_state == BadUsbStateFileError) ||
  509. (worker_state == BadUsbStateScriptError)) { // State: error
  510. uint32_t flags =
  511. bad_usb_flags_get(WorkerEvtEnd, FuriWaitForever); // Waiting for exit command
  512. if(flags & WorkerEvtEnd) {
  513. break;
  514. }
  515. }
  516. }
  517. furi_hal_hid_set_state_callback(NULL, NULL);
  518. storage_file_close(script_file);
  519. storage_file_free(script_file);
  520. furi_string_free(bad_usb->line);
  521. furi_string_free(bad_usb->line_prev);
  522. furi_string_free(bad_usb->string_print);
  523. FURI_LOG_I(WORKER_TAG, "End");
  524. return 0;
  525. }
  526. static void bad_usb_script_set_default_keyboard_layout(BadUsbScript* bad_usb) {
  527. furi_assert(bad_usb);
  528. memset(bad_usb->layout, HID_KEYBOARD_NONE, sizeof(bad_usb->layout));
  529. memcpy(bad_usb->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_usb->layout)));
  530. }
  531. BadUsbScript* bad_usb_script_open(FuriString* file_path) {
  532. furi_assert(file_path);
  533. BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript));
  534. bad_usb->file_path = furi_string_alloc();
  535. furi_string_set(bad_usb->file_path, file_path);
  536. bad_usb_script_set_default_keyboard_layout(bad_usb);
  537. bad_usb->st.state = BadUsbStateInit;
  538. bad_usb->st.error[0] = '\0';
  539. bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb);
  540. furi_thread_start(bad_usb->thread);
  541. return bad_usb;
  542. } //-V773
  543. void bad_usb_script_close(BadUsbScript* bad_usb) {
  544. furi_assert(bad_usb);
  545. furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtEnd);
  546. furi_thread_join(bad_usb->thread);
  547. furi_thread_free(bad_usb->thread);
  548. furi_string_free(bad_usb->file_path);
  549. free(bad_usb);
  550. }
  551. void bad_usb_script_set_keyboard_layout(BadUsbScript* bad_usb, FuriString* layout_path) {
  552. furi_assert(bad_usb);
  553. if((bad_usb->st.state == BadUsbStateRunning) || (bad_usb->st.state == BadUsbStateDelay)) {
  554. // do not update keyboard layout while a script is running
  555. return;
  556. }
  557. File* layout_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
  558. if(!furi_string_empty(layout_path)) { //-V1051
  559. if(storage_file_open(
  560. layout_file, furi_string_get_cstr(layout_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
  561. uint16_t layout[128];
  562. if(storage_file_read(layout_file, layout, sizeof(layout)) == sizeof(layout)) {
  563. memcpy(bad_usb->layout, layout, sizeof(layout));
  564. }
  565. }
  566. storage_file_close(layout_file);
  567. } else {
  568. bad_usb_script_set_default_keyboard_layout(bad_usb);
  569. }
  570. storage_file_free(layout_file);
  571. }
  572. void bad_usb_script_toggle(BadUsbScript* bad_usb) {
  573. furi_assert(bad_usb);
  574. furi_thread_flags_set(furi_thread_get_id(bad_usb->thread), WorkerEvtToggle);
  575. }
  576. BadUsbState* bad_usb_script_get_state(BadUsbScript* bad_usb) {
  577. furi_assert(bad_usb);
  578. return &(bad_usb->st);
  579. }