usb_ccb_start.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. #include "usb_ccb_start.h"
  2. #include <furi.h>
  3. #include <furi_hal_usb_hid.h>
  4. #include <gui/elements.h>
  5. struct UsbCcbStart {
  6. View* view;
  7. };
  8. typedef struct {
  9. bool left_pressed;
  10. bool up_pressed;
  11. bool right_pressed;
  12. bool down_pressed;
  13. bool ok_pressed;
  14. bool back_pressed;
  15. bool connected;
  16. } UsbCcbStartModel;
  17. typedef struct {
  18. uint16_t value;
  19. const char* name;
  20. } HID_CONSUMER;
  21. // All of the strings are prefixed with "HID_CONSUMER_", which has been removed to save some space.
  22. HID_CONSUMER hidConsumerArray[] = {
  23. {0x00, "UNASSIGNED"}, // Generic Consumer Control Device
  24. {0x01, "CONTROL"},
  25. {0x02, "NUMERIC_KEY_PAD"},
  26. {0x03, "PROGRAMMABLE_BUTTONS"},
  27. {0x04, "MICROPHONE"},
  28. {0x05, "HEADPHONE"},
  29. {0x06, "GRAPHIC_EQUALIZER"},
  30. {0x20, "PLUS_10"}, // Numeric Key Pad
  31. {0x21, "PLUS_100"},
  32. {0x22, "AM_PM"},
  33. {0x30, "POWER"}, // General Controls
  34. {0x31, "RESET"},
  35. {0x32, "SLEEP"},
  36. {0x33, "SLEEP_AFTER"},
  37. {0x34, "SLEEP_MODE"},
  38. {0x35, "ILLUMINATION"},
  39. {0x36, "FUNCTION_BUTTONS"},
  40. {0x40, "MENU"}, // Menu Controls
  41. {0x41, "MENU_PICK"},
  42. {0x42, "MENU_UP"},
  43. {0x43, "MENU_DOWN"},
  44. {0x44, "MENU_LEFT"},
  45. {0x45, "MENU_RIGHT"},
  46. {0x46, "MENU_ESCAPE"},
  47. {0x47, "MENU_VALUE_INCREASE"},
  48. {0x48, "MENU_VALUE_DECREASE"},
  49. {0x60, "DATA_ON_SCREEN"}, // Display Controls
  50. {0x61, "CLOSED_CAPTION"},
  51. {0x62, "CLOSED_CAPTION_SELECT"},
  52. {0x63, "VCR_TV"},
  53. {0x64, "BROADCAST_MODE"},
  54. {0x65, "SNAPSHOT"},
  55. {0x66, "STILL"},
  56. {0x80, "SELECTION"}, // Selection Controls
  57. {0x81, "ASSIGN_SELECTION"},
  58. {0x82, "MODE_STEP"},
  59. {0x83, "RECALL_LAST"},
  60. {0x84, "ENTER_CHANNEL"},
  61. {0x85, "ORDER_MOVIE"},
  62. {0x86, "CHANNEL"},
  63. {0x87, "MEDIA_SELECTION"},
  64. {0x88, "MEDIA_SELECT_COMPUTER"},
  65. {0x89, "MEDIA_SELECT_TV"},
  66. {0x8A, "MEDIA_SELECT_WWW"},
  67. {0x8B, "MEDIA_SELECT_DVD"},
  68. {0x8C, "MEDIA_SELECT_TELEPHONE"},
  69. {0x8D, "MEDIA_SELECT_PROGRAM_GUIDE"},
  70. {0x8E, "MEDIA_SELECT_VIDEO_PHONE"},
  71. {0x8F, "MEDIA_SELECT_GAMES"},
  72. {0x90, "MEDIA_SELECT_MESSAGES"},
  73. {0x91, "MEDIA_SELECT_CD"},
  74. {0x92, "MEDIA_SELECT_VCR"},
  75. {0x93, "MEDIA_SELECT_TUNER"},
  76. {0x94, "QUIT"},
  77. {0x95, "HELP"},
  78. {0x96, "MEDIA_SELECT_TAPE"},
  79. {0x97, "MEDIA_SELECT_CABLE"},
  80. {0x98, "MEDIA_SELECT_SATELLITE"},
  81. {0x99, "MEDIA_SELECT_SECURITY"},
  82. {0x9A, "MEDIA_SELECT_HOME"},
  83. {0x9B, "MEDIA_SELECT_CALL"},
  84. {0x9C, "CHANNEL_INCREMENT"},
  85. {0x9D, "CHANNEL_DECREMENT"},
  86. {0x9E, "MEDIA_SELECT_SAP"},
  87. {0xA0, "VCR_PLUS"},
  88. {0xA1, "ONCE"},
  89. {0xA2, "DAILY"},
  90. {0xA3, "WEEKLY"},
  91. {0xA4, "MONTHLY"},
  92. {0xB0, "PLAY"}, // Transport Controls
  93. {0xB1, "PAUSE"},
  94. {0xB2, "RECORD"},
  95. {0xB3, "FAST_FORWARD"},
  96. {0xB4, "REWIND"},
  97. {0xB5, "SCAN_NEXT_TRACK"},
  98. {0xB6, "SCAN_PREVIOUS_TRACK"},
  99. {0xB7, "STOP"},
  100. {0xB8, "EJECT"},
  101. {0xB9, "RANDOM_PLAY"},
  102. {0xBA, "SELECT_DISC"},
  103. {0xBB, "ENTER_DISC"},
  104. {0xBC, "REPEAT"},
  105. {0xBD, "TRACKING"},
  106. {0xBE, "TRACK_NORMAL"},
  107. {0xBF, "SLOW_TRACKING"},
  108. {0xC0, "FRAME_FORWARD"},
  109. {0xC1, "FRAME_BACK"},
  110. {0xC2, "MARK"}, // Search Controls
  111. {0xC3, "CLEAR_MARK"},
  112. {0xC4, "REPEAT_FROM_MARK"},
  113. {0xC5, "RETURN_TO_MARK"},
  114. {0xC6, "SEARCH_MARK_FORWARD"},
  115. {0xC7, "SEARCH_MARK_BACKWARDS"},
  116. {0xC8, "COUNTER_RESET"},
  117. {0xC9, "SHOW_COUNTER"},
  118. {0xCA, "TRACKING_INCREMENT"},
  119. {0xCB, "TRACKING_DECREMENT"},
  120. {0xCC, "STOP_EJECT"},
  121. {0xCD, "PLAY_PAUSE"},
  122. {0xCE, "PLAY_SKIP"},
  123. {0xE0, "VOLUME"}, // Audio Controls
  124. {0xE1, "BALANCE"},
  125. {0xE2, "MUTE"},
  126. {0xE3, "BASS"},
  127. {0xE4, "TREBLE"},
  128. {0xE5, "BASS_BOOST"},
  129. {0xE6, "SURROUND_MODE"},
  130. {0xE7, "LOUDNESS"},
  131. {0xE8, "MPX"},
  132. {0xE9, "VOLUME_INCREMENT"},
  133. {0xEA, "VOLUME_DECREMENT"},
  134. {0xF0, "SPEED_SELECT"}, // Speed Controls
  135. {0xF1, "PLAYBACK_SPEED"},
  136. {0xF2, "STANDARD_PLAY"},
  137. {0xF3, "LONG_PLAY"},
  138. {0xF4, "EXTENDED_PLAY"},
  139. {0xF5, "SLOW"},
  140. {0x100, "FAN_ENABLE"}, // Home and Security Controls
  141. {0x101, "FAN_SPEED"},
  142. {0x102, "LIGHT_ENABLE"},
  143. {0x103, "LIGHT_ILLUMINATION_LEVEL"},
  144. {0x104, "CLIMATE_CONTROL_ENABLE"},
  145. {0x105, "ROOM_TEMPERATURE"},
  146. {0x106, "SECURITY_ENABLE"},
  147. {0x107, "FIRE_ALARM"},
  148. {0x108, "POLICE_ALARM"},
  149. {0x109, "PROXIMITY"},
  150. {0x10A, "MOTION"},
  151. {0x10B, "DURESS_ALARM"},
  152. {0x10C, "HOLDUP_ALARM"},
  153. {0x10D, "MEDICAL_ALARM"},
  154. {0x150, "BALANCE_RIGHT"}, // Speaker Channels
  155. {0x151, "BALANCE_LEFT"},
  156. {0x152, "BASS_INCREMENT"},
  157. {0x153, "BASS_DECREMENT"},
  158. {0x154, "TREBLE_INCREMENT"},
  159. {0x155, "TREBLE_DECREMENT"},
  160. {0x160, "SPEAKER_SYSTEM"},
  161. {0x161, "CHANNEL_LEFT"},
  162. {0x162, "CHANNEL_RIGHT"},
  163. {0x163, "CHANNEL_CENTER"},
  164. {0x164, "CHANNEL_FRONT"},
  165. {0x165, "CHANNEL_CENTER_FRONT"},
  166. {0x166, "CHANNEL_SIDE"},
  167. {0x167, "CHANNEL_SURROUND"},
  168. {0x168, "CHANNEL_LOW_FREQUENCY_ENHANCEMENT"},
  169. {0x169, "CHANNEL_TOP"},
  170. {0x16A, "CHANNEL_UNKNOWN"},
  171. {0x170, "SUB_CHANNEL"}, // PC Theatre
  172. {0x171, "SUB_CHANNEL_INCREMENT"},
  173. {0x172, "SUB_CHANNEL_DECREMENT"},
  174. {0x173, "ALTERNATE_AUDIO_INCREMENT"},
  175. {0x174, "ALTERNATE_AUDIO_DECREMENT"},
  176. {0x180, "APPLICATION_LAUNCH_BUTTONS"}, // Application Launch Buttons
  177. {0x181, "AL_LAUNCH_BUTTON_CONFIGURATION_TOOL"},
  178. {0x182, "AL_PROGRAMMABLE_BUTTON_CONFIGURATION"},
  179. {0x183, "AL_CONSUMER_CONTROL_CONFIGURATION"},
  180. {0x184, "AL_WORD_PROCESSOR"},
  181. {0x185, "AL_TEXT_EDITOR"},
  182. {0x186, "AL_SPREADSHEET"},
  183. {0x187, "AL_GRAPHICS_EDITOR"},
  184. {0x188, "AL_PRESENTATION_APP"},
  185. {0x189, "AL_DATABASE_APP"},
  186. {0x18A, "AL_EMAIL_READER"},
  187. {0x18B, "AL_NEWSREADER"},
  188. {0x18C, "AL_VOICEMAIL"},
  189. {0x18D, "AL_CONTACTS_ADDRESS_BOOK"},
  190. {0x18E, "AL_CALENDAR_SCHEDULE"},
  191. {0x18F, "AL_TASK_PROJECT_MANAGER"},
  192. {0x190, "AL_LOG_JOURNAL_TIMECARD"},
  193. {0x191, "AL_CHECKBOOK_FINANCE"},
  194. {0x192, "AL_CALCULATOR"},
  195. {0x193, "AL_A_V_CAPTURE_PLAYBACK"},
  196. {0x194, "AL_LOCAL_MACHINE_BROWSER"},
  197. {0x195, "AL_LAN_WAN_BROWSER"},
  198. {0x196, "AL_INTERNET_BROWSER"},
  199. {0x197, "AL_REMOTE_NETWORKING_ISP_CONNECT"},
  200. {0x198, "AL_NETWORK_CONFERENCE"},
  201. {0x199, "AL_NETWORK_CHAT"},
  202. {0x19A, "AL_TELEPHONY_DIALER"},
  203. {0x19B, "AL_LOGON"},
  204. {0x19C, "AL_LOGOFF"},
  205. {0x19D, "AL_LOGON_LOGOFF"},
  206. {0x19E, "AL_TERMINAL_LOCK_SCREENSAVER"},
  207. {0x19F, "AL_CONTROL_PANEL"},
  208. {0x1A0, "AL_COMMAND_LINE_PROCESSOR_RUN"},
  209. {0x1A1, "AL_PROCESS_TASK_MANAGER"},
  210. {0x1A2, "AL_SELECT_TASK_APPLICATION"},
  211. {0x1A3, "AL_NEXT_TASK_APPLICATION"},
  212. {0x1A4, "AL_PREVIOUS_TASK_APPLICATION"},
  213. {0x1A5, "AL_PREEMPTIVE_HALT_TASK_APPLICATION"},
  214. {0x1A6, "AL_INTEGRATED_HELP_CENTER"},
  215. {0x1A7, "AL_DOCUMENTS"},
  216. {0x1A8, "AL_THESAURUS"},
  217. {0x1A9, "AL_DICTIONARY"},
  218. {0x1AA, "AL_DESKTOP"},
  219. {0x1AB, "AL_SPELL_CHECK"},
  220. {0x1AC, "AL_GRAMMAR_CHECK"},
  221. {0x1AD, "AL_WIRELESS_STATUS"},
  222. {0x1AE, "AL_KEYBOARD_LAYOUT"},
  223. {0x1AF, "AL_VIRUS_PROTECTION"},
  224. {0x1B0, "AL_ENCRYPTION"},
  225. {0x1B1, "AL_SCREEN_SAVER"},
  226. {0x1B2, "AL_ALARMS"},
  227. {0x1B3, "AL_CLOCK"},
  228. {0x1B4, "AL_FILE_BROWSER"},
  229. {0x1B5, "AL_POWER_STATUS"},
  230. {0x1B6, "AL_IMAGE_BROWSER"},
  231. {0x1B7, "AL_AUDIO_BROWSER"},
  232. {0x1B8, "AL_MOVIE_BROWSER"},
  233. {0x1B9, "AL_DIGITAL_RIGHTS_MANAGER"},
  234. {0x1BA, "AL_DIGITAL_WALLET"},
  235. {0x1BC, "AL_INSTANT_MESSAGING"},
  236. {0x1BD, "AL_OEM_FEATURES_TIPS_TUTORIAL_BROWSER"},
  237. {0x1BE, "AL_OEM_HELP"},
  238. {0x1BF, "AL_ONLINE_COMMUNITY"},
  239. {0x1C0, "AL_ENTERTAINMENT_CONTENT_BROWSER"},
  240. {0x1C1, "AL_ONLINE_SHOPPING_BROWSER"},
  241. {0x1C2, "AL_SMARTCARD_INFORMATION_HELP"},
  242. {0x1C3, "AL_MARKET_MONITOR_FINANCE_BROWSER"},
  243. {0x1C4, "AL_CUSTOMIZED_CORPORATE_NEWS_BROWSER"},
  244. {0x1C5, "AL_ONLINE_ACTIVITY_BROWSER"},
  245. {0x1C6, "AL_RESEARCH_SEARCH_BROWSER"},
  246. {0x1C7, "AL_AUDIO_PLAYER"},
  247. {0x200, "GENERIC_GUI_APPLICATION_CONTROLS"}, // Generic GUI Application Controls
  248. {0x201, "AC_NEW"},
  249. {0x202, "AC_OPEN"},
  250. {0x203, "AC_CLOSE"},
  251. {0x204, "AC_EXIT"},
  252. {0x205, "AC_MAXIMIZE"},
  253. {0x206, "AC_MINIMIZE"},
  254. {0x207, "AC_SAVE"},
  255. {0x208, "AC_PRINT"},
  256. {0x209, "AC_PROPERTIES"},
  257. {0x21A, "AC_UNDO"},
  258. {0x21B, "AC_COPY"},
  259. {0x21C, "AC_CUT"},
  260. {0x21D, "AC_PASTE"},
  261. {0x21E, "AC_SELECT_ALL"},
  262. {0x21F, "AC_FIND"},
  263. {0x220, "AC_FIND_AND_REPLACE"},
  264. {0x221, "AC_SEARCH"},
  265. {0x222, "AC_GO_TO"},
  266. {0x223, "AC_HOME"},
  267. {0x224, "AC_BACK"},
  268. {0x225, "AC_FORWARD"},
  269. {0x226, "AC_STOP"},
  270. {0x227, "AC_REFRESH"},
  271. {0x228, "AC_PREVIOUS_LINK"},
  272. {0x229, "AC_NEXT_LINK"},
  273. {0x22A, "AC_BOOKMARKS"},
  274. {0x22B, "AC_HISTORY"},
  275. {0x22C, "AC_SUBSCRIPTIONS"},
  276. {0x22D, "AC_ZOOM_IN"},
  277. {0x22E, "AC_ZOOM_OUT"},
  278. {0x22F, "AC_ZOOM"},
  279. {0x230, "AC_FULL_SCREEN_VIEW"},
  280. {0x231, "AC_NORMAL_VIEW"},
  281. {0x232, "AC_VIEW_TOGGLE"},
  282. {0x233, "AC_SCROLL_UP"},
  283. {0x234, "AC_SCROLL_DOWN"},
  284. {0x235, "AC_SCROLL"},
  285. {0x236, "AC_PAN_LEFT"},
  286. {0x237, "AC_PAN_RIGHT"},
  287. {0x238, "AC_PAN"},
  288. {0x239, "AC_NEW_WINDOW"},
  289. {0x23A, "AC_TILE_HORIZONTALLY"},
  290. {0x23B, "AC_TILE_VERTICALLY"},
  291. {0x23C, "AC_FORMAT"},
  292. {0x23D, "AC_EDIT"},
  293. {0x23E, "AC_BOLD"},
  294. {0x23F, "AC_ITALICS"},
  295. {0x240, "AC_UNDERLINE"},
  296. {0x241, "AC_STRIKETHROUGH"},
  297. {0x242, "AC_SUBSCRIPT"},
  298. {0x243, "AC_SUPERSCRIPT"},
  299. {0x244, "AC_ALL_CAPS"},
  300. {0x245, "AC_ROTATE"},
  301. {0x246, "AC_RESIZE"},
  302. {0x247, "AC_FLIP_HORIZONTAL"},
  303. {0x248, "AC_FLIP_VERTICAL"},
  304. {0x249, "AC_MIRROR_HORIZONTAL"},
  305. {0x24A, "AC_MIRROR_VERTICAL"},
  306. {0x24B, "AC_FONT_SELECT"},
  307. {0x24C, "AC_FONT_COLOR"},
  308. {0x24D, "AC_FONT_SIZE"},
  309. {0x24E, "AC_JUSTIFY_LEFT"},
  310. {0x24F, "AC_JUSTIFY_CENTER_H"},
  311. {0x250, "AC_JUSTIFY_RIGHT"},
  312. {0x251, "AC_JUSTIFY_BLOCK_H"},
  313. {0x252, "AC_JUSTIFY_TOP"},
  314. {0x253, "AC_JUSTIFY_CENTER_V"},
  315. {0x254, "AC_JUSTIFY_BOTTOM"},
  316. {0x255, "AC_JUSTIFY_BLOCK_V"},
  317. {0x256, "AC_INDENT_DECREASE"},
  318. {0x257, "AC_INDENT_INCREASE"},
  319. {0x258, "AC_NUMBERED_LIST"},
  320. {0x259, "AC_RESTART_NUMBERING"},
  321. {0x25A, "AC_BULLETED_LIST"},
  322. {0x25B, "AC_PROMOTE"},
  323. {0x25C, "AC_DEMOTE"},
  324. {0x25D, "AC_YES"},
  325. {0x25E, "AC_NO"},
  326. {0x25F, "AC_CANCEL"},
  327. {0x260, "AC_CATALOG"},
  328. {0x261, "AC_BUY_CHECKOUT"},
  329. {0x262, "AC_ADD_TO_CART"},
  330. {0x263, "AC_EXPAND"},
  331. {0x264, "AC_EXPAND_ALL"},
  332. {0x265, "AC_COLLAPSE"},
  333. {0x266, "AC_COLLAPSE_ALL"},
  334. {0x267, "AC_PRINT_PREVIEW"},
  335. {0x268, "AC_PASTE_SPECIAL"},
  336. {0x269, "AC_INSERT_MODE"},
  337. {0x26A, "AC_DELETE"},
  338. {0x26B, "AC_LOCK"},
  339. {0x26C, "AC_UNLOCK"},
  340. {0x26D, "AC_PROTECT"},
  341. {0x26E, "AC_UNPROTECT"},
  342. {0x26F, "AC_ATTACH_COMMENT"},
  343. {0x270, "AC_DELETE_COMMENT"},
  344. {0x271, "AC_VIEW_COMMENT"},
  345. {0x272, "AC_SELECT_WORD"},
  346. {0x273, "AC_SELECT_SENTENCE"},
  347. {0x274, "AC_SELECT_PARAGRAPH"},
  348. {0x275, "AC_SELECT_COLUMN"},
  349. {0x276, "AC_SELECT_ROW"},
  350. {0x277, "AC_SELECT_TABLE"},
  351. {0x278, "AC_SELECT_OBJECT"},
  352. {0x279, "AC_REDO_REPEAT"},
  353. {0x27A, "AC_SORT"},
  354. {0x27B, "AC_SORT_ASCENDING"},
  355. {0x27C, "AC_SORT_DESCENDING"},
  356. {0x27D, "AC_FILTER"},
  357. {0x27E, "AC_SET_CLOCK"},
  358. {0x27F, "AC_VIEW_CLOCK"},
  359. {0x280, "AC_SELECT_TIME_ZONE"},
  360. {0x281, "AC_EDIT_TIME_ZONES"},
  361. {0x282, "AC_SET_ALARM"},
  362. {0x283, "AC_CLEAR_ALARM"},
  363. {0x284, "AC_SNOOZE_ALARM"},
  364. {0x285, "AC_RESET_ALARM"},
  365. {0x286, "AC_SYNCHRONIZE"},
  366. {0x287, "AC_SEND_RECEIVE"},
  367. {0x288, "AC_SEND_TO"},
  368. {0x289, "AC_REPLY"},
  369. {0x28A, "AC_REPLY_ALL"},
  370. {0x28B, "AC_FORWARD_MSG"},
  371. {0x28C, "AC_SEND"},
  372. {0x28D, "AC_ATTACH_FILE"},
  373. {0x28E, "AC_UPLOAD"},
  374. {0x28F, "AC_DOWNLOAD_SAVE_TARGET_AS"},
  375. {0x290, "AC_SET_BORDERS"},
  376. {0x291, "AC_INSERT_ROW"},
  377. {0x292, "AC_INSERT_COLUMN"},
  378. {0x293, "AC_INSERT_FILE"},
  379. {0x294, "AC_INSERT_PICTURE"},
  380. {0x295, "AC_INSERT_OBJECT"},
  381. {0x296, "AC_INSERT_SYMBOL"},
  382. {0x297, "AC_SAVE_AND_CLOSE"},
  383. {0x298, "AC_RENAME"},
  384. {0x299, "AC_MERGE"},
  385. {0x29A, "AC_SPLIT"},
  386. {0x29B, "AC_DISRIBUTE_HORIZONTALLY"},
  387. {0x29C, "AC_DISTRIBUTE_VERTICALLY"}};
  388. const int hidConsumerArraySize = sizeof(hidConsumerArray) / sizeof(hidConsumerArray[0]);
  389. void strrev(char* arr, int start, int end) {
  390. char temp;
  391. if(start >= end) return;
  392. temp = *(arr + start);
  393. *(arr + start) = *(arr + end);
  394. *(arr + end) = temp;
  395. start++;
  396. end--;
  397. strrev(arr, start, end);
  398. }
  399. char* itoa(int number, char* arr, int base) {
  400. int i = 0, r, negative = 0;
  401. if(number == 0) {
  402. arr[i] = '0';
  403. arr[i + 1] = '\0';
  404. return arr;
  405. }
  406. if(number < 0 && base == 10) {
  407. number *= -1;
  408. negative = 1;
  409. }
  410. while(number != 0) {
  411. r = number % base;
  412. arr[i] = (r > 9) ? (r - 10) + 'a' : r + '0';
  413. i++;
  414. number /= base;
  415. }
  416. if(negative) {
  417. arr[i] = '-';
  418. i++;
  419. }
  420. strrev(arr, 0, i - 1);
  421. arr[i] = '\0';
  422. return arr;
  423. }
  424. // Function to convert a single hex digit to its character representation
  425. char hexDigitToChar(uint8_t digit) {
  426. if(digit < 10) {
  427. return '0' + digit;
  428. } else {
  429. return 'A' + (digit - 10);
  430. }
  431. }
  432. // Function to convert a uint16_t value to its hex string representation
  433. void uint16ToHexString(uint16_t value, char* hexString) {
  434. hexString[0] = '0';
  435. hexString[1] = 'x';
  436. int startIndex = 2;
  437. for(int i = 3; i >= 0; --i) {
  438. uint8_t digit = (value >> (i * 4)) & 0xF;
  439. if(digit != 0 || startIndex != 2) {
  440. hexString[startIndex++] = hexDigitToChar(digit);
  441. }
  442. }
  443. if(startIndex == 2) { // If there are no non-zero digits, display at least "0x0"
  444. hexString[startIndex++] = '0';
  445. }
  446. hexString[startIndex] = '\0';
  447. }
  448. bool is_running = false;
  449. uint32_t autofire_delay = 1000;
  450. char autofire_delay_str[12];
  451. char hexString[7];
  452. // Start at the Application Launch Buttons by default, since that's the most interesting
  453. int i = 153;
  454. int currentSubsetIndex = 13;
  455. // Array to store indexes of different CCB subsets
  456. // The idea would be to try using these different subsets against different types of devices
  457. int hidConsumerSubsets[] = {
  458. 0, // Generic Consumer Control Device
  459. 7, // Numeric Key Pad
  460. 10, // General Controls
  461. 17, // Menu Controls
  462. 26, // Display Controls
  463. 33, // Selection Controls
  464. 69, // Transport Controls (nice)
  465. 87, // Search Controls
  466. 100, // Audio Controls
  467. 111, // Speed Controls
  468. 117, // Home and Security Controls
  469. 131, // Speaker Channels
  470. 148, // PC Theatre
  471. 153, // Application Launch Buttons
  472. 224 // Generic GUI Application Controls
  473. };
  474. const int hidConsumerSubsetsSize = sizeof(hidConsumerSubsets) / sizeof(hidConsumerSubsets[0]);
  475. const char* getConsumerSubsetName(int i) {
  476. if(i >= 0 && i < 7) {
  477. return "Generic Consumer Control";
  478. } else if(i >= 7 && i < 10) {
  479. return "Numeric Key Pad";
  480. } else if(i >= 10 && i < 17) {
  481. return "General Controls";
  482. } else if(i >= 17 && i < 26) {
  483. return "Menu Controls";
  484. } else if(i >= 26 && i < 33) {
  485. return "Display Controls";
  486. } else if(i >= 33 && i < 69) {
  487. return "Selection Controls";
  488. } else if(i >= 69 && i < 87) {
  489. return "Transport Controls";
  490. } else if(i >= 87 && i < 100) {
  491. return "Search Controls";
  492. } else if(i >= 100 && i < 111) {
  493. return "Audio Controls";
  494. } else if(i >= 111 && i < 117) {
  495. return "Speed Controls";
  496. } else if(i >= 117 && i < 131) {
  497. return "Home and Security Controls";
  498. } else if(i >= 131 && i < 148) {
  499. return "Speaker Channels";
  500. } else if(i >= 148 && i < 153) {
  501. return "PC Theatre";
  502. } else if(i >= 153 && i < 224) {
  503. return "Application Launch Buttons";
  504. } else if(i >= 224) {
  505. return "GUI Application Controls";
  506. }
  507. // Won't ever happen though
  508. return "Invalid Index";
  509. }
  510. // This is the main program loop
  511. static void usb_ccb_start_draw_callback(Canvas* canvas, void* context) {
  512. furi_assert(context);
  513. itoa(autofire_delay, autofire_delay_str, 10);
  514. uint16ToHexString(hidConsumerArray[i].value, hexString);
  515. canvas_clear(canvas);
  516. canvas_set_font(canvas, FontPrimary);
  517. canvas_draw_str(canvas, 0, 10, is_running ? "Running" : "Not running");
  518. canvas_set_font(canvas, FontSecondary);
  519. canvas_draw_str(canvas, 0, 24, "Delay [ms]: ");
  520. canvas_draw_str(canvas, 50, 24, autofire_delay_str);
  521. canvas_draw_str(canvas, 0, 38, "Current key subset:");
  522. canvas_draw_str(canvas, 0, 46, getConsumerSubsetName(i));
  523. canvas_draw_str(
  524. canvas,
  525. 0,
  526. 56,
  527. is_running ? "Sent: HID_CONSUMER_" : "Next: HID_CONSUMER_");
  528. canvas_draw_str(canvas, 24, 56, hexString);
  529. canvas_draw_str(canvas, 0, 64, hidConsumerArray[i].name);
  530. if(is_running) {
  531. uint16_t consumer_key = hidConsumerArray[i].value;
  532. // Sending the consumer control button
  533. furi_delay_us(autofire_delay * 500);
  534. furi_hal_hid_consumer_key_press(consumer_key);
  535. furi_delay_us(2000); // Hold the key pressed for a short amount of time
  536. // Stop sending the consumer control button
  537. furi_hal_hid_consumer_key_release(consumer_key);
  538. furi_delay_us(autofire_delay * 500);
  539. // Cycle onto next consumer control button
  540. i += 1;
  541. // Stop once we've cycled all consumer control buttons
  542. if(i == hidConsumerArraySize) {
  543. i = 0;
  544. is_running = false;
  545. }
  546. }
  547. }
  548. // This function is the controller
  549. static void usb_ccb_start_process(UsbCcbStart* usb_ccb_start, InputEvent* event) {
  550. with_view_model(
  551. usb_ccb_start->view,
  552. UsbCcbStartModel * model,
  553. {
  554. if(event->type == InputTypeLong) {
  555. if(event->key == InputKeyRight) {
  556. model->right_pressed = true;
  557. currentSubsetIndex = (currentSubsetIndex + 1) % hidConsumerSubsetsSize;
  558. i = hidConsumerSubsets[currentSubsetIndex];
  559. } else if(event->key == InputKeyLeft) {
  560. model->left_pressed = true;
  561. currentSubsetIndex =
  562. (currentSubsetIndex - 1 + hidConsumerSubsetsSize) % hidConsumerSubsetsSize;
  563. i = hidConsumerSubsets[currentSubsetIndex];
  564. }
  565. } else if(event->type == InputTypePress) {
  566. if(event->key == InputKeyRight) {
  567. model->right_pressed = true;
  568. i = (i + 1) % hidConsumerArraySize;
  569. } else if(event->key == InputKeyLeft) {
  570. model->left_pressed = true;
  571. i = (i - 1 + hidConsumerArraySize) % hidConsumerArraySize;
  572. } else if(event->key == InputKeyDown) {
  573. model->down_pressed = true;
  574. if(autofire_delay > 0) {
  575. autofire_delay -= 100;
  576. }
  577. } else if(event->key == InputKeyUp) {
  578. model->up_pressed = true;
  579. autofire_delay += 100;
  580. } else if(event->key == InputKeyOk) {
  581. model->ok_pressed = true;
  582. is_running = !is_running;
  583. } else if(event->key == InputKeyBack) {
  584. model->back_pressed = true;
  585. }
  586. } else if(event->type == InputTypeRelease) {
  587. if(event->key == InputKeyUp) {
  588. model->up_pressed = false;
  589. } else if(event->key == InputKeyDown) {
  590. model->down_pressed = false;
  591. } else if(event->key == InputKeyLeft) {
  592. model->left_pressed = false;
  593. } else if(event->key == InputKeyRight) {
  594. model->right_pressed = false;
  595. } else if(event->key == InputKeyOk) {
  596. model->ok_pressed = false;
  597. } else if(event->key == InputKeyBack) {
  598. model->back_pressed = false;
  599. }
  600. } else if(event->type == InputTypeShort) {
  601. if(event->key == InputKeyBack) {
  602. }
  603. }
  604. },
  605. true);
  606. }
  607. static bool usb_ccb_start_input_callback(InputEvent* event, void* context) {
  608. furi_assert(context);
  609. UsbCcbStart* usb_ccb_start = context;
  610. bool consumed = false;
  611. if(event->type == InputTypeLong && event->key == InputKeyBack) {
  612. furi_hal_hid_kb_release_all();
  613. } else {
  614. usb_ccb_start_process(usb_ccb_start, event);
  615. consumed = true;
  616. }
  617. return consumed;
  618. }
  619. UsbCcbStart* usb_ccb_start_alloc() {
  620. UsbCcbStart* usb_ccb_start = malloc(sizeof(UsbCcbStart));
  621. usb_ccb_start->view = view_alloc();
  622. view_set_context(usb_ccb_start->view, usb_ccb_start);
  623. view_allocate_model(usb_ccb_start->view, ViewModelTypeLocking, sizeof(UsbCcbStartModel));
  624. view_set_draw_callback(usb_ccb_start->view, usb_ccb_start_draw_callback);
  625. view_set_input_callback(usb_ccb_start->view, usb_ccb_start_input_callback);
  626. return usb_ccb_start;
  627. }
  628. void usb_ccb_start_free(UsbCcbStart* usb_ccb_start) {
  629. furi_assert(usb_ccb_start);
  630. view_free(usb_ccb_start->view);
  631. free(usb_ccb_start);
  632. i = 0;
  633. }
  634. View* usb_ccb_start_get_view(UsbCcbStart* usb_ccb_start) {
  635. furi_assert(usb_ccb_start);
  636. return usb_ccb_start->view;
  637. }
  638. void usb_ccb_start_set_connected_status(UsbCcbStart* usb_ccb_start, bool connected) {
  639. furi_assert(usb_ccb_start);
  640. with_view_model(
  641. usb_ccb_start->view, UsbCcbStartModel * model, { model->connected = connected; }, true);
  642. }