ducky_script.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  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_bt_hid.h>
  7. #include <bt/bt_service/bt.h>
  8. #include <storage/storage.h>
  9. #include "ducky_script.h"
  10. #include "ducky_script_i.h"
  11. #include <dolphin/dolphin.h>
  12. #include <toolbox/hex.h>
  13. #include "../bad_bt_app.h"
  14. const uint8_t BAD_BT_BOUND_MAC_ADDRESS[BAD_BT_MAC_ADDRESS_LEN] =
  15. {0x41, 0x4a, 0xef, 0xb6, 0xa9, 0xd4};
  16. const uint8_t BAD_BT_EMPTY_MAC_ADDRESS[BAD_BT_MAC_ADDRESS_LEN] =
  17. {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  18. #define TAG "BadBT"
  19. #define WORKER_TAG TAG "Worker"
  20. #define BADBT_ASCII_TO_KEY(script, x) \
  21. (((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE)
  22. /**
  23. * Delays for waiting between HID key press and key release
  24. */
  25. const uint8_t bt_hid_delays[LevelRssiNum] = {
  26. 60, // LevelRssi122_100
  27. 55, // LevelRssi99_80
  28. 50, // LevelRssi79_60
  29. 47, // LevelRssi59_40
  30. 34, // LevelRssi39_0
  31. };
  32. uint8_t bt_timeout = 0;
  33. static LevelRssiRange bt_remote_rssi_range(Bt* bt) {
  34. uint8_t rssi;
  35. if(!bt_remote_rssi(bt, &rssi)) return LevelRssiError;
  36. if(rssi <= 39)
  37. return LevelRssi39_0;
  38. else if(rssi <= 59)
  39. return LevelRssi59_40;
  40. else if(rssi <= 79)
  41. return LevelRssi79_60;
  42. else if(rssi <= 99)
  43. return LevelRssi99_80;
  44. else if(rssi <= 122)
  45. return LevelRssi122_100;
  46. return LevelRssiError;
  47. }
  48. static inline void update_bt_timeout(Bt* bt) {
  49. LevelRssiRange r = bt_remote_rssi_range(bt);
  50. if(r < LevelRssiNum) {
  51. bt_timeout = bt_hid_delays[r];
  52. FURI_LOG_D(WORKER_TAG, "BLE Key timeout : %u", bt_timeout);
  53. }
  54. }
  55. typedef enum {
  56. WorkerEvtStartStop = (1 << 0),
  57. WorkerEvtPauseResume = (1 << 1),
  58. WorkerEvtEnd = (1 << 2),
  59. WorkerEvtConnect = (1 << 3),
  60. WorkerEvtDisconnect = (1 << 4),
  61. } WorkerEvtFlags;
  62. static const char ducky_cmd_id[] = {"ID"};
  63. static const char ducky_cmd_bt_id[] = {"BT_ID"};
  64. static const uint8_t numpad_keys[10] = {
  65. HID_KEYPAD_0,
  66. HID_KEYPAD_1,
  67. HID_KEYPAD_2,
  68. HID_KEYPAD_3,
  69. HID_KEYPAD_4,
  70. HID_KEYPAD_5,
  71. HID_KEYPAD_6,
  72. HID_KEYPAD_7,
  73. HID_KEYPAD_8,
  74. HID_KEYPAD_9,
  75. };
  76. uint32_t ducky_get_command_len(const char* line) {
  77. uint32_t len = strlen(line);
  78. for(uint32_t i = 0; i < len; i++) {
  79. if(line[i] == ' ') return i;
  80. }
  81. return 0;
  82. }
  83. bool ducky_is_line_end(const char chr) {
  84. return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n'));
  85. }
  86. uint16_t ducky_get_keycode(BadBtScript* bad_bt, const char* param, bool accept_chars) {
  87. uint16_t keycode = ducky_get_keycode_by_name(param);
  88. if(keycode != HID_KEYBOARD_NONE) {
  89. return keycode;
  90. }
  91. if((accept_chars) && (strlen(param) > 0)) {
  92. return (BADBT_ASCII_TO_KEY(bad_bt, param[0]) & 0xFF);
  93. }
  94. return 0;
  95. }
  96. bool ducky_get_number(const char* param, uint32_t* val) {
  97. uint32_t value = 0;
  98. if(sscanf(param, "%lu", &value) == 1) {
  99. *val = value;
  100. return true;
  101. }
  102. return false;
  103. }
  104. void ducky_numlock_on(BadBtScript* bad_bt) {
  105. UNUSED(bad_bt);
  106. if((furi_hal_bt_hid_get_led_state() & HID_KB_LED_NUM) == 0) {
  107. furi_hal_bt_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK);
  108. furi_delay_ms(bt_timeout);
  109. furi_hal_bt_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK);
  110. }
  111. }
  112. bool ducky_numpad_press(BadBtScript* bad_bt, const char num) {
  113. UNUSED(bad_bt);
  114. if((num < '0') || (num > '9')) return false;
  115. uint16_t key = numpad_keys[num - '0'];
  116. furi_hal_bt_hid_kb_press(key);
  117. furi_delay_ms(bt_timeout);
  118. furi_hal_bt_hid_kb_release(key);
  119. return true;
  120. }
  121. bool ducky_altchar(BadBtScript* bad_bt, const char* charcode) {
  122. uint8_t i = 0;
  123. bool state = false;
  124. furi_hal_bt_hid_kb_press(KEY_MOD_LEFT_ALT);
  125. while(!ducky_is_line_end(charcode[i])) {
  126. state = ducky_numpad_press(bad_bt, charcode[i]);
  127. if(state == false) break;
  128. i++;
  129. }
  130. furi_hal_bt_hid_kb_release(KEY_MOD_LEFT_ALT);
  131. return state;
  132. }
  133. bool ducky_altstring(BadBtScript* bad_bt, const char* param) {
  134. uint32_t i = 0;
  135. bool state = false;
  136. while(param[i] != '\0') {
  137. if((param[i] < ' ') || (param[i] > '~')) {
  138. i++;
  139. continue; // Skip non-printable chars
  140. }
  141. char temp_str[4];
  142. snprintf(temp_str, 4, "%u", param[i]);
  143. state = ducky_altchar(bad_bt, temp_str);
  144. if(state == false) break;
  145. i++;
  146. }
  147. return state;
  148. }
  149. int32_t ducky_error(BadBtScript* bad_bt, const char* text, ...) {
  150. va_list args;
  151. va_start(args, text);
  152. vsnprintf(bad_bt->st.error, sizeof(bad_bt->st.error), text, args);
  153. va_end(args);
  154. return SCRIPT_STATE_ERROR;
  155. }
  156. bool ducky_string(BadBtScript* bad_bt, const char* param) {
  157. uint32_t i = 0;
  158. while(param[i] != '\0') {
  159. if(param[i] != '\n') {
  160. uint16_t keycode = BADBT_ASCII_TO_KEY(bad_bt, param[i]);
  161. if(keycode != HID_KEYBOARD_NONE) {
  162. furi_hal_bt_hid_kb_press(keycode);
  163. furi_delay_ms(bt_timeout);
  164. furi_hal_bt_hid_kb_release(keycode);
  165. }
  166. } else {
  167. furi_hal_bt_hid_kb_press(HID_KEYBOARD_RETURN);
  168. furi_delay_ms(bt_timeout);
  169. furi_hal_bt_hid_kb_release(HID_KEYBOARD_RETURN);
  170. }
  171. i++;
  172. }
  173. bad_bt->stringdelay = 0;
  174. return true;
  175. }
  176. static bool ducky_string_next(BadBtScript* bad_bt) {
  177. if(bad_bt->string_print_pos >= furi_string_size(bad_bt->string_print)) {
  178. return true;
  179. }
  180. char print_char = furi_string_get_char(bad_bt->string_print, bad_bt->string_print_pos);
  181. if(print_char != '\n') {
  182. uint16_t keycode = BADBT_ASCII_TO_KEY(bad_bt, print_char);
  183. if(keycode != HID_KEYBOARD_NONE) {
  184. furi_hal_bt_hid_kb_press(keycode);
  185. furi_delay_ms(bt_timeout);
  186. furi_hal_bt_hid_kb_release(keycode);
  187. }
  188. } else {
  189. furi_hal_bt_hid_kb_press(HID_KEYBOARD_RETURN);
  190. furi_delay_ms(bt_timeout);
  191. furi_hal_bt_hid_kb_release(HID_KEYBOARD_RETURN);
  192. }
  193. bad_bt->string_print_pos++;
  194. return false;
  195. }
  196. static int32_t ducky_parse_line(BadBtScript* bad_bt, FuriString* line) {
  197. uint32_t line_len = furi_string_size(line);
  198. const char* line_tmp = furi_string_get_cstr(line);
  199. if(line_len == 0) {
  200. return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
  201. }
  202. FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp);
  203. // Ducky Lang Functions
  204. int32_t cmd_result = ducky_execute_cmd(bad_bt, line_tmp);
  205. if(cmd_result != SCRIPT_STATE_CMD_UNKNOWN) {
  206. return cmd_result;
  207. }
  208. // Special keys + modifiers
  209. uint16_t key = ducky_get_keycode(bad_bt, line_tmp, false);
  210. if(key == HID_KEYBOARD_NONE) {
  211. return ducky_error(bad_bt, "No keycode defined for %s", line_tmp);
  212. }
  213. if((key & 0xFF00) != 0) {
  214. // It's a modifier key
  215. uint32_t offset = ducky_get_command_len(line_tmp) + 1;
  216. // ducky_get_command_len() returns 0 without space, so check for != 1
  217. if(offset != 1 && line_len > offset) {
  218. // It's also a key combination
  219. key |= ducky_get_keycode(bad_bt, line_tmp + offset, true);
  220. }
  221. }
  222. furi_hal_bt_hid_kb_press(key);
  223. furi_delay_ms(bt_timeout);
  224. furi_hal_bt_hid_kb_release(key);
  225. return 0;
  226. }
  227. static bool ducky_set_bt_id(BadBtScript* bad_bt, const char* line) {
  228. size_t line_len = strlen(line);
  229. size_t mac_len = BAD_BT_MAC_ADDRESS_LEN * 3;
  230. if(line_len < mac_len + 1) return false; // MAC + at least 1 char for name
  231. uint8_t mac[BAD_BT_MAC_ADDRESS_LEN];
  232. for(size_t i = 0; i < BAD_BT_MAC_ADDRESS_LEN; i++) {
  233. char a = line[i * 3];
  234. char b = line[i * 3 + 1];
  235. if((a < 'A' && a > 'F') || (a < '0' && a > '9') || (b < 'A' && b > 'F') ||
  236. (b < '0' && b > '9') || !hex_char_to_uint8(a, b, &mac[i])) {
  237. return false;
  238. }
  239. }
  240. furi_hal_bt_reverse_mac_addr(mac);
  241. furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, line + mac_len);
  242. bt_set_profile_mac_address(bad_bt->bt, mac);
  243. return true;
  244. }
  245. static bool ducky_script_preload(BadBtScript* bad_bt, File* script_file) {
  246. uint8_t ret = 0;
  247. uint32_t line_len = 0;
  248. furi_string_reset(bad_bt->line);
  249. do {
  250. ret = storage_file_read(script_file, bad_bt->file_buf, FILE_BUFFER_LEN);
  251. for(uint16_t i = 0; i < ret; i++) {
  252. if(bad_bt->file_buf[i] == '\n' && line_len > 0) {
  253. bad_bt->st.line_nb++;
  254. line_len = 0;
  255. } else {
  256. if(bad_bt->st.line_nb == 0) { // Save first line
  257. furi_string_push_back(bad_bt->line, bad_bt->file_buf[i]);
  258. }
  259. line_len++;
  260. }
  261. }
  262. if(storage_file_eof(script_file)) {
  263. if(line_len > 0) {
  264. bad_bt->st.line_nb++;
  265. break;
  266. }
  267. }
  268. } while(ret > 0);
  269. const char* line_tmp = furi_string_get_cstr(bad_bt->line);
  270. if(bad_bt->app->switch_mode_thread) {
  271. furi_thread_join(bad_bt->app->switch_mode_thread);
  272. furi_thread_free(bad_bt->app->switch_mode_thread);
  273. bad_bt->app->switch_mode_thread = NULL;
  274. }
  275. // Looking for ID or BT_ID command at first line
  276. bad_bt->set_usb_id = false;
  277. bad_bt->set_bt_id = false;
  278. bad_bt->has_usb_id = strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0;
  279. // TODO: We setting has_usb_id to its value but ignoring it for now and not using anywhere here, may be used in a future to detect script type
  280. bad_bt->has_bt_id = strncmp(line_tmp, ducky_cmd_bt_id, strlen(ducky_cmd_bt_id)) == 0;
  281. if(bad_bt->has_bt_id) {
  282. if(!bad_bt->app->bt_remember) {
  283. bad_bt->set_bt_id = ducky_set_bt_id(bad_bt, &line_tmp[strlen(ducky_cmd_bt_id) + 1]);
  284. }
  285. }
  286. bad_kb_config_refresh_menu(bad_bt->app);
  287. if(!bad_bt->set_bt_id) {
  288. const char* bt_name = bad_bt->app->config.bt_name;
  289. const uint8_t* bt_mac = bad_bt->app->bt_remember ? (uint8_t*)&BAD_BT_BOUND_MAC_ADDRESS :
  290. bad_bt->app->config.bt_mac;
  291. bool reset_name = strncmp(
  292. bt_name,
  293. furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard),
  294. BAD_BT_ADV_NAME_MAX_LEN);
  295. bool reset_mac = memcmp(
  296. bt_mac,
  297. furi_hal_bt_get_profile_mac_addr(FuriHalBtProfileHidKeyboard),
  298. BAD_BT_MAC_ADDRESS_LEN);
  299. if(reset_name && reset_mac) {
  300. furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, bt_name);
  301. } else if(reset_name) {
  302. bt_set_profile_adv_name(bad_bt->bt, bt_name);
  303. }
  304. if(reset_mac) {
  305. bt_set_profile_mac_address(bad_bt->bt, bt_mac);
  306. }
  307. }
  308. storage_file_seek(script_file, 0, true);
  309. furi_string_reset(bad_bt->line);
  310. return true;
  311. }
  312. static int32_t ducky_script_execute_next(BadBtScript* bad_bt, File* script_file) {
  313. int32_t delay_val = 0;
  314. if(bad_bt->repeat_cnt > 0) {
  315. bad_bt->repeat_cnt--;
  316. delay_val = ducky_parse_line(bad_bt, bad_bt->line_prev);
  317. if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
  318. return 0;
  319. } else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
  320. return delay_val;
  321. } else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
  322. return delay_val;
  323. } else if(delay_val < 0) { // Script error
  324. bad_bt->st.error_line = bad_bt->st.line_cur - 1;
  325. FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_bt->st.line_cur - 1U);
  326. return SCRIPT_STATE_ERROR;
  327. } else {
  328. return (delay_val + bad_bt->defdelay);
  329. }
  330. }
  331. furi_string_set(bad_bt->line_prev, bad_bt->line);
  332. furi_string_reset(bad_bt->line);
  333. while(1) {
  334. if(bad_bt->buf_len == 0) {
  335. bad_bt->buf_len = storage_file_read(script_file, bad_bt->file_buf, FILE_BUFFER_LEN);
  336. if(storage_file_eof(script_file)) {
  337. if((bad_bt->buf_len < FILE_BUFFER_LEN) && (bad_bt->file_end == false)) {
  338. bad_bt->file_buf[bad_bt->buf_len] = '\n';
  339. bad_bt->buf_len++;
  340. bad_bt->file_end = true;
  341. }
  342. }
  343. bad_bt->buf_start = 0;
  344. if(bad_bt->buf_len == 0) return SCRIPT_STATE_END;
  345. }
  346. for(uint8_t i = bad_bt->buf_start; i < (bad_bt->buf_start + bad_bt->buf_len); i++) {
  347. if(bad_bt->file_buf[i] == '\n' && furi_string_size(bad_bt->line) > 0) {
  348. bad_bt->st.line_cur++;
  349. bad_bt->buf_len = bad_bt->buf_len + bad_bt->buf_start - (i + 1);
  350. bad_bt->buf_start = i + 1;
  351. furi_string_trim(bad_bt->line);
  352. delay_val = ducky_parse_line(bad_bt, bad_bt->line);
  353. if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
  354. return 0;
  355. } else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
  356. return delay_val;
  357. } else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
  358. return delay_val;
  359. } else if(delay_val < 0) {
  360. bad_bt->st.error_line = bad_bt->st.line_cur;
  361. FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_bt->st.line_cur);
  362. return SCRIPT_STATE_ERROR;
  363. } else {
  364. return (delay_val + bad_bt->defdelay);
  365. }
  366. } else {
  367. furi_string_push_back(bad_bt->line, bad_bt->file_buf[i]);
  368. }
  369. }
  370. bad_bt->buf_len = 0;
  371. if(bad_bt->file_end) return SCRIPT_STATE_END;
  372. }
  373. return 0;
  374. }
  375. static void bad_bt_bt_hid_state_callback(BtStatus status, void* context) {
  376. furi_assert(context);
  377. BadBtScript* bad_bt = context;
  378. bool state = (status == BtStatusConnected);
  379. if(state == true) {
  380. LevelRssiRange r = bt_remote_rssi_range(bad_bt->bt);
  381. if(r != LevelRssiError) {
  382. bt_timeout = bt_hid_delays[r];
  383. }
  384. furi_thread_flags_set(furi_thread_get_id(bad_bt->thread), WorkerEvtConnect);
  385. } else {
  386. furi_thread_flags_set(furi_thread_get_id(bad_bt->thread), WorkerEvtDisconnect);
  387. }
  388. }
  389. static uint32_t bad_bt_flags_get(uint32_t flags_mask, uint32_t timeout) {
  390. uint32_t flags = furi_thread_flags_get();
  391. furi_check((flags & FuriFlagError) == 0);
  392. if(flags == 0) {
  393. flags = furi_thread_flags_wait(flags_mask, FuriFlagWaitAny, timeout);
  394. furi_check(((flags & FuriFlagError) == 0) || (flags == (unsigned)FuriFlagErrorTimeout));
  395. } else {
  396. uint32_t state = furi_thread_flags_clear(flags);
  397. furi_check((state & FuriFlagError) == 0);
  398. }
  399. return flags;
  400. }
  401. static int32_t bad_bt_worker(void* context) {
  402. BadBtScript* bad_bt = context;
  403. BadBtWorkerState worker_state = BadBtStateInit;
  404. int32_t delay_val = 0;
  405. FURI_LOG_I(WORKER_TAG, "Init");
  406. File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
  407. bad_bt->line = furi_string_alloc();
  408. bad_bt->line_prev = furi_string_alloc();
  409. bad_bt->string_print = furi_string_alloc();
  410. bt_set_status_changed_callback(bad_bt->bt, bad_bt_bt_hid_state_callback, bad_bt);
  411. while(1) {
  412. if(worker_state == BadBtStateInit) { // State: initialization
  413. if(storage_file_open(
  414. script_file,
  415. furi_string_get_cstr(bad_bt->file_path),
  416. FSAM_READ,
  417. FSOM_OPEN_EXISTING)) {
  418. if((ducky_script_preload(bad_bt, script_file)) && (bad_bt->st.line_nb > 0)) {
  419. if(furi_hal_bt_is_connected()) {
  420. worker_state = BadBtStateIdle; // Ready to run
  421. } else {
  422. worker_state = BadBtStateNotConnected; // Not connected
  423. }
  424. } else {
  425. worker_state = BadBtStateScriptError; // Script preload error
  426. }
  427. } else {
  428. FURI_LOG_E(WORKER_TAG, "File open error");
  429. worker_state = BadBtStateFileError; // File open error
  430. }
  431. bad_bt->st.state = worker_state;
  432. } else if(worker_state == BadBtStateNotConnected) { // State: Not connected
  433. uint32_t flags = bad_bt_flags_get(
  434. WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop,
  435. FuriWaitForever);
  436. if(flags & WorkerEvtEnd) {
  437. break;
  438. } else if(flags & WorkerEvtConnect) {
  439. worker_state = BadBtStateIdle; // Ready to run
  440. } else if(flags & WorkerEvtStartStop) {
  441. worker_state = BadBtStateWillRun; // Will run when connected
  442. }
  443. bad_bt->st.state = worker_state;
  444. } else if(worker_state == BadBtStateIdle) { // State: ready to start
  445. uint32_t flags = bad_bt_flags_get(
  446. WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtConnect | WorkerEvtDisconnect,
  447. FuriWaitForever);
  448. if(flags & WorkerEvtEnd) {
  449. break;
  450. } else if(flags & WorkerEvtStartStop) { // Start executing script
  451. delay_val = 0;
  452. bad_bt->buf_len = 0;
  453. bad_bt->st.line_cur = 0;
  454. bad_bt->defdelay = 0;
  455. bad_bt->stringdelay = 0;
  456. bad_bt->repeat_cnt = 0;
  457. bad_bt->key_hold_nb = 0;
  458. bad_bt->file_end = false;
  459. storage_file_seek(script_file, 0, true);
  460. bad_bt_script_set_keyboard_layout(bad_bt, bad_bt->keyboard_layout);
  461. worker_state = BadBtStateRunning;
  462. } else if(flags & WorkerEvtDisconnect) {
  463. worker_state = BadBtStateNotConnected; // Disconnected
  464. }
  465. bad_bt->st.state = worker_state;
  466. } else if(worker_state == BadBtStateWillRun) { // State: start on connection
  467. uint32_t flags = bad_bt_flags_get(
  468. WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop,
  469. FuriWaitForever);
  470. if(flags & WorkerEvtEnd) {
  471. break;
  472. } else if(flags & WorkerEvtConnect) { // Start executing script
  473. delay_val = 0;
  474. bad_bt->buf_len = 0;
  475. bad_bt->st.line_cur = 0;
  476. bad_bt->defdelay = 0;
  477. bad_bt->stringdelay = 0;
  478. bad_bt->repeat_cnt = 0;
  479. bad_bt->file_end = false;
  480. storage_file_seek(script_file, 0, true);
  481. // extra time for PC to recognize Flipper as keyboard
  482. flags = furi_thread_flags_wait(
  483. WorkerEvtEnd | WorkerEvtDisconnect | WorkerEvtStartStop,
  484. FuriFlagWaitAny | FuriFlagNoClear,
  485. 1500);
  486. if(flags == (unsigned)FuriFlagErrorTimeout) {
  487. // If nothing happened - start script execution
  488. worker_state = BadBtStateRunning;
  489. } else if(flags & WorkerEvtStartStop) {
  490. worker_state = BadBtStateIdle;
  491. furi_thread_flags_clear(WorkerEvtStartStop);
  492. }
  493. update_bt_timeout(bad_bt->bt);
  494. bad_bt_script_set_keyboard_layout(bad_bt, bad_bt->keyboard_layout);
  495. } else if(flags & WorkerEvtStartStop) { // Cancel scheduled execution
  496. worker_state = BadBtStateNotConnected;
  497. }
  498. bad_bt->st.state = worker_state;
  499. } else if(worker_state == BadBtStateRunning) { // State: running
  500. uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val);
  501. uint32_t flags = furi_thread_flags_wait(
  502. WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtConnect | WorkerEvtDisconnect,
  503. FuriFlagWaitAny,
  504. delay_cur);
  505. delay_val -= delay_cur;
  506. if(!(flags & FuriFlagError)) {
  507. if(flags & WorkerEvtEnd) {
  508. break;
  509. } else if(flags & WorkerEvtStartStop) {
  510. worker_state = BadBtStateIdle; // Stop executing script
  511. furi_hal_bt_hid_kb_release_all();
  512. } else if(flags & WorkerEvtDisconnect) {
  513. worker_state = BadBtStateNotConnected; // Disconnected
  514. furi_hal_bt_hid_kb_release_all();
  515. }
  516. bad_bt->st.state = worker_state;
  517. continue;
  518. } else if(
  519. (flags == (unsigned)FuriFlagErrorTimeout) ||
  520. (flags == (unsigned)FuriFlagErrorResource)) {
  521. if(delay_val > 0) {
  522. bad_bt->st.delay_remain--;
  523. continue;
  524. }
  525. bad_bt->st.state = BadBtStateRunning;
  526. delay_val = ducky_script_execute_next(bad_bt, script_file);
  527. if(delay_val == SCRIPT_STATE_ERROR) { // Script error
  528. delay_val = 0;
  529. worker_state = BadBtStateScriptError;
  530. bad_bt->st.state = worker_state;
  531. furi_hal_bt_hid_kb_release_all();
  532. } else if(delay_val == SCRIPT_STATE_END) { // End of script
  533. delay_val = 0;
  534. worker_state = BadBtStateIdle;
  535. bad_bt->st.state = BadBtStateDone;
  536. furi_hal_bt_hid_kb_release_all();
  537. continue;
  538. } else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays
  539. delay_val = bad_bt->defdelay;
  540. bad_bt->string_print_pos = 0;
  541. worker_state = BadBtStateStringDelay;
  542. } else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // set state to wait for user input
  543. worker_state = BadBtStateWaitForBtn;
  544. bad_bt->st.state = BadBtStateWaitForBtn; // Show long delays
  545. } else if(delay_val > 1000) {
  546. bad_bt->st.state = BadBtStateDelay; // Show long delays
  547. bad_bt->st.delay_remain = delay_val / 1000;
  548. }
  549. } else {
  550. furi_check((flags & FuriFlagError) == 0);
  551. }
  552. } else if(worker_state == BadBtStateWaitForBtn) { // State: Wait for button Press
  553. uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val);
  554. uint32_t flags = furi_thread_flags_wait(
  555. WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtConnect |
  556. WorkerEvtDisconnect,
  557. FuriFlagWaitAny,
  558. delay_cur);
  559. if(!(flags & FuriFlagError)) {
  560. if(flags & WorkerEvtEnd) {
  561. break;
  562. } else if(flags & WorkerEvtStartStop) {
  563. delay_val = 0;
  564. worker_state = BadBtStateRunning;
  565. } else if(flags & WorkerEvtDisconnect) {
  566. worker_state = BadBtStateNotConnected; // Disconnected
  567. furi_hal_hid_kb_release_all();
  568. }
  569. bad_bt->st.state = worker_state;
  570. continue;
  571. }
  572. } else if(worker_state == BadBtStateStringDelay) { // State: print string with delays
  573. uint32_t flags = furi_thread_flags_wait(
  574. WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtConnect |
  575. WorkerEvtDisconnect,
  576. FuriFlagWaitAny,
  577. bad_bt->stringdelay);
  578. if(!(flags & FuriFlagError)) {
  579. if(flags & WorkerEvtEnd) {
  580. break;
  581. } else if(flags & WorkerEvtStartStop) {
  582. worker_state = BadBtStateIdle; // Stop executing script
  583. furi_hal_bt_hid_kb_release_all();
  584. } else if(flags & WorkerEvtDisconnect) {
  585. worker_state = BadBtStateNotConnected; // Disconnected
  586. furi_hal_bt_hid_kb_release_all();
  587. }
  588. bad_bt->st.state = worker_state;
  589. continue;
  590. } else if(
  591. (flags == (unsigned)FuriFlagErrorTimeout) ||
  592. (flags == (unsigned)FuriFlagErrorResource)) {
  593. bool string_end = ducky_string_next(bad_bt);
  594. if(string_end) {
  595. bad_bt->stringdelay = 0;
  596. worker_state = BadBtStateRunning;
  597. }
  598. } else {
  599. furi_check((flags & FuriFlagError) == 0);
  600. }
  601. } else if(
  602. (worker_state == BadBtStateFileError) ||
  603. (worker_state == BadBtStateScriptError)) { // State: error
  604. uint32_t flags =
  605. bad_bt_flags_get(WorkerEvtEnd, FuriWaitForever); // Waiting for exit command
  606. if(flags & WorkerEvtEnd) {
  607. break;
  608. }
  609. }
  610. update_bt_timeout(bad_bt->bt);
  611. }
  612. bt_set_status_changed_callback(bad_bt->bt, NULL, NULL);
  613. storage_file_close(script_file);
  614. storage_file_free(script_file);
  615. furi_string_free(bad_bt->line);
  616. furi_string_free(bad_bt->line_prev);
  617. furi_string_free(bad_bt->string_print);
  618. FURI_LOG_I(WORKER_TAG, "End");
  619. return 0;
  620. }
  621. static void bad_bt_script_set_default_keyboard_layout(BadBtScript* bad_bt) {
  622. furi_assert(bad_bt);
  623. furi_string_set_str(bad_bt->keyboard_layout, "");
  624. memset(bad_bt->layout, HID_KEYBOARD_NONE, sizeof(bad_bt->layout));
  625. memcpy(bad_bt->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_bt->layout)));
  626. }
  627. BadBtScript* bad_bt_script_open(FuriString* file_path, Bt* bt, BadBtApp* app) {
  628. furi_assert(file_path);
  629. BadBtScript* bad_bt = malloc(sizeof(BadBtScript));
  630. bad_bt->app = app;
  631. bad_bt->file_path = furi_string_alloc();
  632. furi_string_set(bad_bt->file_path, file_path);
  633. bad_bt->keyboard_layout = furi_string_alloc();
  634. bad_bt_script_set_default_keyboard_layout(bad_bt);
  635. bad_bt->st.state = BadBtStateInit;
  636. bad_bt->st.error[0] = '\0';
  637. bad_bt->bt = bt;
  638. bad_bt->thread = furi_thread_alloc_ex("BadBtWorker", 2048, bad_bt_worker, bad_bt);
  639. furi_thread_start(bad_bt->thread);
  640. return bad_bt;
  641. }
  642. void bad_bt_script_close(BadBtScript* bad_bt) {
  643. furi_assert(bad_bt);
  644. furi_record_close(RECORD_STORAGE);
  645. furi_thread_flags_set(furi_thread_get_id(bad_bt->thread), WorkerEvtEnd);
  646. furi_thread_join(bad_bt->thread);
  647. furi_thread_free(bad_bt->thread);
  648. furi_string_free(bad_bt->file_path);
  649. furi_string_free(bad_bt->keyboard_layout);
  650. free(bad_bt);
  651. }
  652. void bad_bt_script_set_keyboard_layout(BadBtScript* bad_bt, FuriString* layout_path) {
  653. furi_assert(bad_bt);
  654. if((bad_bt->st.state == BadBtStateRunning) || (bad_bt->st.state == BadBtStateDelay)) {
  655. // do not update keyboard layout while a script is running
  656. return;
  657. }
  658. File* layout_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
  659. if(!furi_string_empty(layout_path)) { //-V1051
  660. furi_string_set(bad_bt->keyboard_layout, layout_path);
  661. if(storage_file_open(
  662. layout_file, furi_string_get_cstr(layout_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
  663. uint16_t layout[128];
  664. if(storage_file_read(layout_file, layout, sizeof(layout)) == sizeof(layout)) {
  665. memcpy(bad_bt->layout, layout, sizeof(layout));
  666. }
  667. }
  668. storage_file_close(layout_file);
  669. } else {
  670. bad_bt_script_set_default_keyboard_layout(bad_bt);
  671. }
  672. storage_file_free(layout_file);
  673. }
  674. void bad_bt_script_toggle(BadBtScript* bad_bt) {
  675. furi_assert(bad_bt);
  676. furi_thread_flags_set(furi_thread_get_id(bad_bt->thread), WorkerEvtStartStop);
  677. }
  678. BadBtState* bad_bt_script_get_state(BadBtScript* bad_bt) {
  679. furi_assert(bad_bt);
  680. return &(bad_bt->st);
  681. }