hid_tikshorts.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. #include "hid_tikshorts.h"
  2. #include "../hid.h"
  3. #include <gui/elements.h>
  4. #include "hid_icons.h"
  5. #define TAG "HidTikShorts"
  6. struct HidTikShorts {
  7. View* view;
  8. Hid* hid;
  9. };
  10. typedef struct {
  11. bool left_pressed;
  12. bool up_pressed;
  13. bool right_pressed;
  14. bool down_pressed;
  15. bool ok_pressed;
  16. bool connected;
  17. bool is_cursor_set;
  18. bool back_mouse_pressed;
  19. HidTransport transport;
  20. } HidTikShortsModel;
  21. static void hid_tikshorts_draw_callback(Canvas* canvas, void* context) {
  22. furi_assert(context);
  23. HidTikShortsModel* model = context;
  24. // Header
  25. if(model->transport == HidTransportBle) {
  26. if(model->connected) {
  27. canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
  28. } else {
  29. canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
  30. }
  31. }
  32. canvas_set_font(canvas, FontPrimary);
  33. elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "TikTok /");
  34. elements_multiline_text_aligned(canvas, 3, 18, AlignLeft, AlignTop, "YT Shorts");
  35. canvas_set_font(canvas, FontSecondary);
  36. // Keypad circles
  37. canvas_draw_icon(canvas, 58, 3, &I_OutCircles_70x51);
  38. // Pause
  39. if(model->back_mouse_pressed) {
  40. canvas_set_bitmap_mode(canvas, 1);
  41. canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19);
  42. canvas_set_bitmap_mode(canvas, 0);
  43. canvas_set_color(canvas, ColorWhite);
  44. }
  45. canvas_draw_icon(canvas, 113, 37, &I_Pause_icon_9x9);
  46. canvas_set_color(canvas, ColorBlack);
  47. // Up
  48. if(model->up_pressed) {
  49. canvas_set_bitmap_mode(canvas, 1);
  50. canvas_draw_icon(canvas, 68, 6, &I_S_UP_31x15);
  51. canvas_set_bitmap_mode(canvas, 0);
  52. canvas_set_color(canvas, ColorWhite);
  53. }
  54. canvas_draw_icon(canvas, 80, 8, &I_Arr_up_7x9);
  55. canvas_set_color(canvas, ColorBlack);
  56. // Down
  57. if(model->down_pressed) {
  58. canvas_set_bitmap_mode(canvas, 1);
  59. canvas_draw_icon(canvas, 68, 36, &I_S_DOWN_31x15);
  60. canvas_set_bitmap_mode(canvas, 0);
  61. canvas_set_color(canvas, ColorWhite);
  62. }
  63. canvas_draw_icon(canvas, 80, 40, &I_Arr_dwn_7x9);
  64. canvas_set_color(canvas, ColorBlack);
  65. // Left
  66. if(model->left_pressed) {
  67. canvas_set_bitmap_mode(canvas, 1);
  68. canvas_draw_icon(canvas, 61, 13, &I_S_LEFT_15x31);
  69. canvas_set_bitmap_mode(canvas, 0);
  70. canvas_set_color(canvas, ColorWhite);
  71. }
  72. canvas_draw_icon(canvas, 64, 25, &I_Voldwn_6x6);
  73. canvas_set_color(canvas, ColorBlack);
  74. // Right
  75. if(model->right_pressed) {
  76. canvas_set_bitmap_mode(canvas, 1);
  77. canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT_15x31);
  78. canvas_set_bitmap_mode(canvas, 0);
  79. canvas_set_color(canvas, ColorWhite);
  80. }
  81. canvas_draw_icon(canvas, 95, 25, &I_Volup_8x6);
  82. canvas_set_color(canvas, ColorBlack);
  83. // Ok
  84. if(model->ok_pressed) {
  85. canvas_set_bitmap_mode(canvas, 1);
  86. canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19);
  87. canvas_set_bitmap_mode(canvas, 0);
  88. canvas_set_color(canvas, ColorWhite);
  89. }
  90. canvas_draw_icon(canvas, 78, 25, &I_Like_def_11x9);
  91. canvas_set_color(canvas, ColorBlack);
  92. // Exit
  93. canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8);
  94. canvas_set_font(canvas, FontSecondary);
  95. elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit");
  96. }
  97. static void hid_tikshorts_reset_cursor(HidTikShorts* hid_tikshorts) {
  98. // Set cursor to the phone's left up corner
  99. // Delays to guarantee one packet per connection interval
  100. for(size_t i = 0; i < 8; i++) {
  101. hid_hal_mouse_move(hid_tikshorts->hid, -127, -127);
  102. furi_delay_ms(50);
  103. }
  104. // Move cursor from the corner
  105. hid_hal_mouse_move(hid_tikshorts->hid, 20, 120);
  106. furi_delay_ms(50);
  107. }
  108. static void hid_tikshorts_process_press(
  109. HidTikShorts* hid_tikshorts,
  110. HidTikShortsModel* model,
  111. InputEvent* event) {
  112. if(event->key == InputKeyUp) {
  113. model->up_pressed = true;
  114. } else if(event->key == InputKeyDown) {
  115. model->down_pressed = true;
  116. } else if(event->key == InputKeyLeft) {
  117. model->left_pressed = true;
  118. hid_hal_consumer_key_press(hid_tikshorts->hid, HID_CONSUMER_VOLUME_DECREMENT);
  119. } else if(event->key == InputKeyRight) {
  120. model->right_pressed = true;
  121. hid_hal_consumer_key_press(hid_tikshorts->hid, HID_CONSUMER_VOLUME_INCREMENT);
  122. } else if(event->key == InputKeyOk) {
  123. model->ok_pressed = true;
  124. } else if(event->key == InputKeyBack) {
  125. model->back_mouse_pressed = true;
  126. }
  127. }
  128. static void hid_tikshorts_process_release(
  129. HidTikShorts* hid_tikshorts,
  130. HidTikShortsModel* model,
  131. InputEvent* event) {
  132. if(event->key == InputKeyUp) {
  133. model->up_pressed = false;
  134. } else if(event->key == InputKeyDown) {
  135. model->down_pressed = false;
  136. } else if(event->key == InputKeyLeft) {
  137. model->left_pressed = false;
  138. hid_hal_consumer_key_release(hid_tikshorts->hid, HID_CONSUMER_VOLUME_DECREMENT);
  139. } else if(event->key == InputKeyRight) {
  140. model->right_pressed = false;
  141. hid_hal_consumer_key_release(hid_tikshorts->hid, HID_CONSUMER_VOLUME_INCREMENT);
  142. } else if(event->key == InputKeyOk) {
  143. model->ok_pressed = false;
  144. } else if(event->key == InputKeyBack) {
  145. model->back_mouse_pressed = false;
  146. }
  147. }
  148. static bool hid_tikshorts_input_callback(InputEvent* event, void* context) {
  149. furi_assert(context);
  150. HidTikShorts* hid_tikshorts = context;
  151. bool consumed = false;
  152. with_view_model(
  153. hid_tikshorts->view,
  154. HidTikShortsModel * model,
  155. {
  156. if(event->type == InputTypePress) {
  157. hid_tikshorts_process_press(hid_tikshorts, model, event);
  158. if(model->connected && !model->is_cursor_set) {
  159. hid_tikshorts_reset_cursor(hid_tikshorts);
  160. model->is_cursor_set = true;
  161. }
  162. consumed = true;
  163. } else if(event->type == InputTypeRelease) {
  164. hid_tikshorts_process_release(hid_tikshorts, model, event);
  165. consumed = true;
  166. } else if(event->type == InputTypeShort) {
  167. if(event->key == InputKeyOk) {
  168. hid_hal_mouse_press(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT);
  169. furi_delay_ms(25);
  170. hid_hal_mouse_release(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT);
  171. furi_delay_ms(100);
  172. hid_hal_mouse_press(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT);
  173. furi_delay_ms(25);
  174. hid_hal_mouse_release(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT);
  175. consumed = true;
  176. } else if(event->key == InputKeyDown) {
  177. // Swipe to next video
  178. hid_hal_mouse_scroll(hid_tikshorts->hid, 6);
  179. hid_hal_mouse_scroll(hid_tikshorts->hid, 8);
  180. hid_hal_mouse_scroll(hid_tikshorts->hid, 10);
  181. hid_hal_mouse_scroll(hid_tikshorts->hid, 8);
  182. hid_hal_mouse_scroll(hid_tikshorts->hid, 6);
  183. consumed = true;
  184. } else if(event->key == InputKeyUp) {
  185. // Swipe to previous video
  186. hid_hal_mouse_scroll(hid_tikshorts->hid, -6);
  187. hid_hal_mouse_scroll(hid_tikshorts->hid, -8);
  188. hid_hal_mouse_scroll(hid_tikshorts->hid, -10);
  189. hid_hal_mouse_scroll(hid_tikshorts->hid, -8);
  190. hid_hal_mouse_scroll(hid_tikshorts->hid, -6);
  191. consumed = true;
  192. } else if(event->key == InputKeyBack) {
  193. // Pause
  194. hid_hal_mouse_press(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT);
  195. furi_delay_ms(50);
  196. hid_hal_mouse_release(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT);
  197. consumed = true;
  198. }
  199. } else if(event->type == InputTypeLong) {
  200. if(event->key == InputKeyBack) {
  201. hid_hal_consumer_key_release_all(hid_tikshorts->hid);
  202. model->is_cursor_set = false;
  203. consumed = false;
  204. }
  205. }
  206. },
  207. true);
  208. return consumed;
  209. }
  210. HidTikShorts* hid_tikshorts_alloc(Hid* bt_hid) {
  211. HidTikShorts* hid_tikshorts = malloc(sizeof(HidTikShorts));
  212. hid_tikshorts->hid = bt_hid;
  213. hid_tikshorts->view = view_alloc();
  214. view_set_context(hid_tikshorts->view, hid_tikshorts);
  215. view_allocate_model(hid_tikshorts->view, ViewModelTypeLocking, sizeof(HidTikShortsModel));
  216. view_set_draw_callback(hid_tikshorts->view, hid_tikshorts_draw_callback);
  217. view_set_input_callback(hid_tikshorts->view, hid_tikshorts_input_callback);
  218. with_view_model(
  219. hid_tikshorts->view,
  220. HidTikShortsModel * model,
  221. { model->transport = bt_hid->transport; },
  222. true);
  223. return hid_tikshorts;
  224. }
  225. void hid_tikshorts_free(HidTikShorts* hid_tikshorts) {
  226. furi_assert(hid_tikshorts);
  227. view_free(hid_tikshorts->view);
  228. free(hid_tikshorts);
  229. }
  230. View* hid_tikshorts_get_view(HidTikShorts* hid_tikshorts) {
  231. furi_assert(hid_tikshorts);
  232. return hid_tikshorts->view;
  233. }
  234. void hid_tikshorts_set_connected_status(HidTikShorts* hid_tikshorts, bool connected) {
  235. furi_assert(hid_tikshorts);
  236. with_view_model(
  237. hid_tikshorts->view,
  238. HidTikShortsModel * model,
  239. {
  240. model->connected = connected;
  241. model->is_cursor_set = false;
  242. },
  243. true);
  244. }