hid_mouse_clicker.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #include "hid_mouse_clicker.h"
  2. #include <gui/elements.h>
  3. #include "../hid.h"
  4. #include "hid_icons.h"
  5. #define TAG "HidMouseClicker"
  6. #define DEFAULT_CLICK_RATE 1
  7. #define MAXIMUM_CLICK_RATE 60
  8. struct HidMouseClicker {
  9. View* view;
  10. Hid* hid;
  11. FuriTimer* timer;
  12. };
  13. typedef struct {
  14. bool connected;
  15. bool running;
  16. int rate;
  17. HidTransport transport;
  18. } HidMouseClickerModel;
  19. static void hid_mouse_clicker_start_or_restart_timer(void* context) {
  20. furi_assert(context);
  21. HidMouseClicker* hid_mouse_clicker = context;
  22. if(furi_timer_is_running(hid_mouse_clicker->timer)) {
  23. furi_timer_stop(hid_mouse_clicker->timer);
  24. }
  25. with_view_model(
  26. hid_mouse_clicker->view,
  27. HidMouseClickerModel * model,
  28. {
  29. furi_timer_start(
  30. hid_mouse_clicker->timer, furi_kernel_get_tick_frequency() / model->rate);
  31. },
  32. true);
  33. }
  34. static void hid_mouse_clicker_draw_callback(Canvas* canvas, void* context) {
  35. furi_assert(context);
  36. HidMouseClickerModel* model = context;
  37. // Header
  38. if(model->transport == HidTransportBle) {
  39. if(model->connected) {
  40. canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
  41. } else {
  42. canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
  43. }
  44. }
  45. canvas_set_font(canvas, FontPrimary);
  46. elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Clicker");
  47. // Ok
  48. canvas_draw_icon(canvas, 63, 25, &I_Space_65x18);
  49. if(model->running) {
  50. canvas_set_font(canvas, FontPrimary);
  51. FuriString* rate_label = furi_string_alloc();
  52. furi_string_printf(rate_label, "%d clicks/s\n\nUp / Down", model->rate);
  53. elements_multiline_text(canvas, AlignLeft, 35, furi_string_get_cstr(rate_label));
  54. canvas_set_font(canvas, FontSecondary);
  55. furi_string_free(rate_label);
  56. elements_slightly_rounded_box(canvas, 66, 27, 60, 13);
  57. canvas_set_color(canvas, ColorWhite);
  58. } else {
  59. canvas_set_font(canvas, FontPrimary);
  60. elements_multiline_text(canvas, AlignLeft, 35, "Press Start\nto start\nclicking");
  61. canvas_set_font(canvas, FontSecondary);
  62. }
  63. canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9);
  64. if(model->running) {
  65. elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Stop");
  66. } else {
  67. elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Start");
  68. }
  69. canvas_set_color(canvas, ColorBlack);
  70. // Back
  71. canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8);
  72. elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Quit");
  73. }
  74. static void hid_mouse_clicker_timer_callback(void* context) {
  75. furi_assert(context);
  76. HidMouseClicker* hid_mouse_clicker = context;
  77. with_view_model(
  78. hid_mouse_clicker->view,
  79. HidMouseClickerModel * model,
  80. {
  81. if(model->running) {
  82. hid_hal_mouse_press(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT);
  83. hid_hal_mouse_release(hid_mouse_clicker->hid, HID_MOUSE_BTN_LEFT);
  84. }
  85. },
  86. false);
  87. }
  88. static void hid_mouse_clicker_enter_callback(void* context) {
  89. hid_mouse_clicker_start_or_restart_timer(context);
  90. }
  91. static void hid_mouse_clicker_exit_callback(void* context) {
  92. furi_assert(context);
  93. HidMouseClicker* hid_mouse_clicker = context;
  94. furi_timer_stop(hid_mouse_clicker->timer);
  95. }
  96. static bool hid_mouse_clicker_input_callback(InputEvent* event, void* context) {
  97. furi_assert(context);
  98. HidMouseClicker* hid_mouse_clicker = context;
  99. bool consumed = false;
  100. bool rate_changed = false;
  101. if(event->type != InputTypeShort && event->type != InputTypeRepeat) {
  102. return false;
  103. }
  104. with_view_model(
  105. hid_mouse_clicker->view,
  106. HidMouseClickerModel * model,
  107. {
  108. switch(event->key) {
  109. case InputKeyOk:
  110. model->running = !model->running;
  111. consumed = true;
  112. break;
  113. case InputKeyUp:
  114. if(model->rate < MAXIMUM_CLICK_RATE) {
  115. model->rate++;
  116. }
  117. rate_changed = true;
  118. consumed = true;
  119. break;
  120. case InputKeyDown:
  121. if(model->rate > 1) {
  122. model->rate--;
  123. }
  124. rate_changed = true;
  125. consumed = true;
  126. break;
  127. default:
  128. consumed = true;
  129. break;
  130. }
  131. },
  132. true);
  133. if(rate_changed) {
  134. hid_mouse_clicker_start_or_restart_timer(context);
  135. }
  136. return consumed;
  137. }
  138. HidMouseClicker* hid_mouse_clicker_alloc(Hid* hid) {
  139. HidMouseClicker* hid_mouse_clicker = malloc(sizeof(HidMouseClicker));
  140. hid_mouse_clicker->view = view_alloc();
  141. view_set_context(hid_mouse_clicker->view, hid_mouse_clicker);
  142. view_allocate_model(
  143. hid_mouse_clicker->view, ViewModelTypeLocking, sizeof(HidMouseClickerModel));
  144. view_set_draw_callback(hid_mouse_clicker->view, hid_mouse_clicker_draw_callback);
  145. view_set_input_callback(hid_mouse_clicker->view, hid_mouse_clicker_input_callback);
  146. view_set_enter_callback(hid_mouse_clicker->view, hid_mouse_clicker_enter_callback);
  147. view_set_exit_callback(hid_mouse_clicker->view, hid_mouse_clicker_exit_callback);
  148. hid_mouse_clicker->hid = hid;
  149. hid_mouse_clicker->timer = furi_timer_alloc(
  150. hid_mouse_clicker_timer_callback, FuriTimerTypePeriodic, hid_mouse_clicker);
  151. with_view_model(
  152. hid_mouse_clicker->view,
  153. HidMouseClickerModel * model,
  154. {
  155. model->transport = hid->transport;
  156. model->rate = DEFAULT_CLICK_RATE;
  157. },
  158. true);
  159. return hid_mouse_clicker;
  160. }
  161. void hid_mouse_clicker_free(HidMouseClicker* hid_mouse_clicker) {
  162. furi_assert(hid_mouse_clicker);
  163. furi_timer_stop(hid_mouse_clicker->timer);
  164. furi_timer_free(hid_mouse_clicker->timer);
  165. view_free(hid_mouse_clicker->view);
  166. free(hid_mouse_clicker);
  167. }
  168. View* hid_mouse_clicker_get_view(HidMouseClicker* hid_mouse_clicker) {
  169. furi_assert(hid_mouse_clicker);
  170. return hid_mouse_clicker->view;
  171. }
  172. void hid_mouse_clicker_set_connected_status(HidMouseClicker* hid_mouse_clicker, bool connected) {
  173. furi_assert(hid_mouse_clicker);
  174. with_view_model(
  175. hid_mouse_clicker->view,
  176. HidMouseClickerModel * model,
  177. { model->connected = connected; },
  178. true);
  179. }