hid_ptt.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. #include "hid_ptt.h"
  2. #include <gui/elements.h>
  3. #include <notification/notification_messages.h>
  4. #include "../hid.h"
  5. #include "../views.h"
  6. #include "hid_icons.h"
  7. #define TAG "HidPtt"
  8. struct HidPtt {
  9. View* view;
  10. Hid* hid;
  11. };
  12. typedef struct {
  13. bool left_pressed;
  14. bool up_pressed;
  15. bool right_pressed;
  16. bool down_pressed;
  17. bool muted;
  18. bool ptt_pressed;
  19. bool connected;
  20. bool is_mac_os;
  21. uint32_t appIndex;
  22. HidTransport transport;
  23. } HidPttModel;
  24. enum HidPttAppIndex {
  25. HidPttAppIndexGoogleMeet,
  26. HidPttAppIndexZoom,
  27. HidPttAppIndexFaceTime,
  28. HidPttAppIndexSkype,
  29. HidPttAppIndexSize,
  30. };
  31. static void hid_ptt_draw_callback(Canvas* canvas, void* context) {
  32. furi_assert(context);
  33. HidPttModel* model = context;
  34. // Header
  35. canvas_set_font(canvas, FontPrimary);
  36. if(model->transport == HidTransportBle) {
  37. if(model->connected) {
  38. canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
  39. } else {
  40. canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
  41. }
  42. }
  43. // App selection
  44. const uint8_t y_app = 78;
  45. canvas_set_font(canvas, FontSecondary);
  46. canvas_draw_icon(canvas, 0, y_app, &I_ButtonLeft_4x7);
  47. if(model->appIndex == HidPttAppIndexGoogleMeet) {
  48. elements_multiline_text_aligned(canvas, 7, y_app, AlignLeft, AlignTop, "Google Meet");
  49. } else if(model->appIndex == HidPttAppIndexZoom) {
  50. elements_multiline_text_aligned(canvas, 7, y_app, AlignLeft, AlignTop, "Zoom");
  51. } else if(model->appIndex == HidPttAppIndexFaceTime) {
  52. elements_multiline_text_aligned(canvas, 7, y_app, AlignLeft, AlignTop, "FaceTime");
  53. } else if(model->appIndex == HidPttAppIndexSkype) {
  54. elements_multiline_text_aligned(canvas, 7, y_app, AlignLeft, AlignTop, "Skype");
  55. }
  56. canvas_draw_icon(canvas, 60, y_app, &I_ButtonRight_4x7);
  57. // OS selection
  58. const uint8_t y_os = 88;
  59. elements_slightly_rounded_box(canvas, model->is_mac_os ? 0 : 26, y_os, model->is_mac_os ? 21 : 26, 11);
  60. canvas_set_color(canvas, model->is_mac_os ? ColorWhite : ColorBlack);
  61. elements_multiline_text_aligned(canvas, 2, y_os + 1, AlignLeft, AlignTop, "Mac");
  62. canvas_set_color(canvas, ColorBlack);
  63. if (model->appIndex != HidPttAppIndexFaceTime) {
  64. elements_multiline_text_aligned(canvas, 23, y_os + 2, AlignLeft, AlignTop, "|");
  65. canvas_set_color(canvas, model->is_mac_os ? ColorBlack : ColorWhite);
  66. elements_multiline_text_aligned(canvas, 28, y_os + 2, AlignLeft, AlignTop, "Linux");
  67. canvas_set_color(canvas, ColorBlack);
  68. }
  69. // Mic label
  70. const uint8_t y_mic = 102;
  71. canvas_draw_icon(canvas, 19, y_mic - 1, &I_Ok_btn_9x9);
  72. elements_multiline_text_aligned(canvas, 0, y_mic, AlignLeft, AlignTop, "Hold to sync");
  73. elements_multiline_text_aligned(canvas, 20, y_mic+10, AlignLeft, AlignTop, "mic status");
  74. // Exit label
  75. canvas_draw_icon(canvas, 20, 121, &I_ButtonLeft_4x7);
  76. elements_multiline_text_aligned(canvas, 0, 121, AlignLeft, AlignTop, "Hold to exit");
  77. const uint8_t x_2 = 27;
  78. const uint8_t x_1 = 8;
  79. const uint8_t x_3 = 46;
  80. const uint8_t y_1 = 19;
  81. const uint8_t y_2 = 38;
  82. const uint8_t y_3 = 57;
  83. // Up
  84. canvas_draw_icon(canvas, x_2, y_1, &I_Button_18x18);
  85. if(model->up_pressed) {
  86. elements_slightly_rounded_box(canvas, x_2 + 3, y_1 + 2, 13, 13);
  87. canvas_set_color(canvas, ColorWhite);
  88. }
  89. if(model->ptt_pressed) {
  90. if (model->appIndex != HidPttAppIndexFaceTime) {
  91. elements_multiline_text_aligned(canvas, x_2 + 4, y_1 + 5, AlignLeft, AlignTop, "OS");
  92. }
  93. } else {
  94. canvas_draw_icon(canvas, x_2 + 5, y_1 + 5, &I_Volup_8x6);
  95. }
  96. canvas_set_color(canvas, ColorBlack);
  97. // Down
  98. canvas_draw_icon(canvas, x_2, y_3, &I_Button_18x18);
  99. if(model->down_pressed) {
  100. elements_slightly_rounded_box(canvas, x_2 + 3, y_3 + 2, 13, 13);
  101. canvas_set_color(canvas, ColorWhite);
  102. }
  103. if(!model->ptt_pressed) {
  104. canvas_draw_icon(canvas, x_2 + 6, y_3 + 5, &I_Voldwn_6x6);
  105. }
  106. canvas_set_color(canvas, ColorBlack);
  107. // Left
  108. canvas_draw_icon(canvas, x_1, y_2, &I_Button_18x18);
  109. if(model->left_pressed) {
  110. elements_slightly_rounded_box(canvas, x_1 + 3, y_2 + 2, 13, 13);
  111. canvas_set_color(canvas, ColorWhite);
  112. }
  113. if (model->ptt_pressed) {
  114. canvas_draw_icon(canvas, x_1 + 7, y_2 + 5, &I_ButtonLeft_4x7);
  115. } else {
  116. canvas_draw_icon(canvas, x_1 + 4, y_2 + 5, &I_Pin_back_arrow_10x8);
  117. }
  118. canvas_set_color(canvas, ColorBlack);
  119. // Right / Camera
  120. canvas_draw_icon(canvas, x_3, y_2, &I_Button_18x18);
  121. if(model->right_pressed) {
  122. elements_slightly_rounded_box(canvas, x_3 + 7, y_2 + 2, 13, 13);
  123. canvas_set_color(canvas, ColorWhite);
  124. }
  125. if(!model->ptt_pressed) {
  126. canvas_draw_icon(canvas, x_3 + 11, y_2 + 5, &I_ButtonLeft_4x7);
  127. canvas_draw_box(canvas, x_3 + 4, y_2 + 5, 7, 7);
  128. } else {
  129. canvas_draw_icon(canvas, x_3 + 8, y_2 + 5, &I_ButtonRight_4x7);
  130. }
  131. canvas_set_color(canvas, ColorBlack);
  132. // Ok / Mic
  133. canvas_draw_icon(canvas, x_2, y_2, &I_Button_18x18);
  134. canvas_draw_icon(canvas, x_2 + 5, y_2 + 4, &I_Mic_btn_8x10);
  135. if(model->muted && !model->ptt_pressed) {
  136. canvas_draw_line(canvas, x_2 + 3, y_2 + 2, x_2 + 3 + 13, y_2 + 2 + 13);
  137. canvas_draw_line(canvas, x_2 + 2, y_2 + 2, x_2 + 2 + 13, y_2 + 2 + 13);
  138. canvas_draw_line(canvas, x_2 + 3, y_2 + 2 + 13, x_2 + 3 + 13, y_2 + 2);
  139. canvas_draw_line(canvas, x_2 + 2, y_2 + 2 + 13, x_2 + 2 + 13, y_2 + 2);
  140. }
  141. canvas_set_color(canvas, ColorBlack);
  142. // Back / PTT
  143. canvas_draw_icon(canvas, x_2, 0, &I_BtnFrameLeft_3x18);
  144. canvas_draw_icon(canvas, x_2 + 35, 0, &I_BtnFrameRight_2x18);
  145. canvas_draw_line(canvas, x_2 + 3, 0, x_2 + 34, 0);
  146. canvas_draw_line(canvas, x_2 + 3, 16, x_2 + 34, 16);
  147. canvas_draw_line(canvas, x_2 + 3, 17, x_2 + 34, 17);
  148. if(model->ptt_pressed) {
  149. elements_slightly_rounded_box(canvas, x_2+3, 0+2, 32, 13);
  150. canvas_set_color(canvas, ColorWhite);
  151. }
  152. canvas_draw_icon(canvas, x_2+4, 0+4, &I_Pin_back_arrow_rotated_8x10);
  153. elements_multiline_text_aligned(canvas, x_2+16, 0+12, AlignLeft, AlignBottom, "PTT");
  154. }
  155. static void hid_ptt_trigger_mute(HidPtt* hid_ptt, HidPttModel * model) {
  156. if(model->appIndex == HidPttAppIndexGoogleMeet && model->is_mac_os) {
  157. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_D);
  158. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_D );
  159. } else if(model->appIndex == HidPttAppIndexGoogleMeet && !model->is_mac_os) {
  160. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_D);
  161. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_D );
  162. } else if(model->appIndex == HidPttAppIndexZoom && model->is_mac_os) {
  163. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_A);
  164. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_A );
  165. } else if(model->appIndex == HidPttAppIndexFaceTime) {
  166. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M);
  167. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M );
  168. } else if(model->appIndex == HidPttAppIndexSkype && model->is_mac_os) {
  169. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M);
  170. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M );
  171. } else if(model->appIndex == HidPttAppIndexSkype && !model->is_mac_os) {
  172. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M);
  173. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M );
  174. }
  175. }
  176. static void hid_ptt_trigger_camera(HidPtt* hid_ptt, HidPttModel * model) {
  177. if(model->appIndex == HidPttAppIndexGoogleMeet && model->is_mac_os) {
  178. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_E);
  179. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_E );
  180. } else if(model->appIndex == HidPttAppIndexGoogleMeet && !model->is_mac_os) {
  181. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_E);
  182. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_E );
  183. } else if(model->appIndex == HidPttAppIndexZoom && model->is_mac_os) {
  184. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V);
  185. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V );
  186. } else if(model->appIndex == HidPttAppIndexZoom && !model->is_mac_os) {
  187. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_V);
  188. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_V );
  189. } else if(model->appIndex == HidPttAppIndexSkype && model->is_mac_os) {
  190. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K);
  191. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K );
  192. } else if(model->appIndex == HidPttAppIndexSkype && !model->is_mac_os) {
  193. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K);
  194. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K );
  195. }
  196. }
  197. static void hid_ptt_start_ptt(HidPtt* hid_ptt, HidPttModel * model) {
  198. if(model->appIndex == HidPttAppIndexGoogleMeet) {
  199. hid_hal_keyboard_press(hid_ptt->hid, HID_KEYBOARD_SPACEBAR);
  200. } else if(model->appIndex == HidPttAppIndexZoom) {
  201. hid_hal_keyboard_press(hid_ptt->hid, HID_KEYBOARD_SPACEBAR);
  202. } else if(model->appIndex == HidPttAppIndexFaceTime) {
  203. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M);
  204. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M );
  205. } else if(model->appIndex == HidPttAppIndexSkype && model->is_mac_os) {
  206. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M);
  207. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M );
  208. } else if(model->appIndex == HidPttAppIndexSkype && !model->is_mac_os) {
  209. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M);
  210. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M );
  211. }
  212. }
  213. static void hid_ptt_stop_ptt(HidPtt* hid_ptt, HidPttModel * model) {
  214. if(model->appIndex == HidPttAppIndexGoogleMeet) {
  215. hid_hal_keyboard_release(hid_ptt->hid, HID_KEYBOARD_SPACEBAR);
  216. } else if(model->appIndex == HidPttAppIndexZoom) {
  217. hid_hal_keyboard_release(hid_ptt->hid, HID_KEYBOARD_SPACEBAR);
  218. } else if(model->appIndex == HidPttAppIndexFaceTime) {
  219. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M);
  220. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M );
  221. } else if(model->appIndex == HidPttAppIndexSkype && model->is_mac_os) {
  222. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M);
  223. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M );
  224. } else if(model->appIndex == HidPttAppIndexSkype && !model->is_mac_os) {
  225. hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M);
  226. hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M );
  227. }
  228. }
  229. // Supports only ±1
  230. static void hid_ptt_shift_app(HidPttModel * model, int shift) {
  231. int i = (short) model->appIndex;
  232. if (i + shift >= HidPttAppIndexSize) {
  233. model->appIndex = 0;
  234. } else if(i + shift <= 0) {
  235. model->appIndex = HidPttAppIndexSize - 1;
  236. } else {
  237. model->appIndex += shift;
  238. }
  239. // Avoid showing facetime if not macos
  240. if (model->appIndex == HidPttAppIndexFaceTime && !model->is_mac_os) {
  241. hid_ptt_shift_app(model, shift);
  242. }
  243. }
  244. static void hid_ptt_process(HidPtt* hid_ptt, InputEvent* event) {
  245. with_view_model(
  246. hid_ptt->view,
  247. HidPttModel * model,
  248. {
  249. if(event->type == InputTypePress) {
  250. if(event->key == InputKeyUp) {
  251. model->up_pressed = true;
  252. if (!model->ptt_pressed){
  253. hid_hal_consumer_key_press(hid_ptt->hid, HID_CONSUMER_VOLUME_INCREMENT);
  254. } else {
  255. if (model->appIndex != HidPttAppIndexFaceTime) {
  256. model->is_mac_os = !model->is_mac_os;
  257. notification_message(hid_ptt->hid->notifications, &sequence_single_vibro);
  258. }
  259. }
  260. } else if(event->key == InputKeyDown) {
  261. model->down_pressed = true;
  262. if (!model->ptt_pressed){
  263. hid_hal_consumer_key_press(hid_ptt->hid, HID_CONSUMER_VOLUME_DECREMENT);
  264. } else {
  265. hid_ptt_shift_app(model, - 1);
  266. notification_message(hid_ptt->hid->notifications, &sequence_single_vibro);
  267. }
  268. } else if(event->key == InputKeyLeft) {
  269. model->left_pressed = true;
  270. if (model->ptt_pressed){
  271. hid_ptt_shift_app(model, 1);
  272. notification_message(hid_ptt->hid->notifications, &sequence_single_vibro);
  273. }
  274. } else if(event->key == InputKeyRight) {
  275. model->right_pressed = true;
  276. if (model->ptt_pressed){
  277. hid_ptt_shift_app(model, - 1);
  278. notification_message(hid_ptt->hid->notifications, &sequence_single_vibro);
  279. }
  280. } else if(event->key == InputKeyBack) {
  281. model->ptt_pressed = true;
  282. if (model->muted) {
  283. hid_ptt_start_ptt(hid_ptt, model);
  284. }
  285. }
  286. } else if(event->type == InputTypeRelease) {
  287. if(event->key == InputKeyUp) {
  288. model->up_pressed = false;
  289. if (!model->ptt_pressed){
  290. hid_hal_consumer_key_release(hid_ptt->hid, HID_CONSUMER_VOLUME_INCREMENT);
  291. }
  292. } else if(event->key == InputKeyDown) {
  293. model->down_pressed = false;
  294. if (!model->ptt_pressed){
  295. hid_hal_consumer_key_release(hid_ptt->hid, HID_CONSUMER_VOLUME_DECREMENT);
  296. }
  297. } else if(event->key == InputKeyLeft) {
  298. model->left_pressed = false;
  299. } else if(event->key == InputKeyRight) {
  300. model->right_pressed = false;
  301. } else if(event->key == InputKeyBack) {
  302. model->ptt_pressed = false;
  303. if (model->muted) {
  304. hid_ptt_stop_ptt(hid_ptt, model);
  305. } else {
  306. hid_ptt_trigger_mute(hid_ptt, model);
  307. model->muted = true;
  308. }
  309. }
  310. } else if(event->type == InputTypeShort) {
  311. if(event->key == InputKeyOk && !model->ptt_pressed ) { // no changes if PTT is pressed
  312. model->muted = !model->muted;
  313. hid_ptt_trigger_mute(hid_ptt, model);
  314. } else if(event->key == InputKeyRight) {
  315. if (!model->ptt_pressed){
  316. hid_ptt_trigger_camera(hid_ptt, model);
  317. }
  318. }
  319. } else if(event->type == InputTypeLong) {
  320. if(event->key == InputKeyLeft) {
  321. model->left_pressed = false;
  322. if (!model->ptt_pressed){
  323. hid_hal_keyboard_release_all(hid_ptt->hid);
  324. view_dispatcher_switch_to_view(hid_ptt->hid->view_dispatcher, HidViewSubmenu);
  325. // sequence_double_vibro to notify that we quit PTT
  326. notification_message(hid_ptt->hid->notifications, &sequence_double_vibro);
  327. }
  328. } else if(event->key == InputKeyOk && !model->ptt_pressed ) { // no changes if PTT is pressed
  329. // Change local mic status
  330. model->muted = !model->muted;
  331. notification_message(hid_ptt->hid->notifications, &sequence_single_vibro);
  332. }
  333. }
  334. //LED
  335. if (model->muted && !model->ptt_pressed) {
  336. notification_message(hid_ptt->hid->notifications, &sequence_reset_red);
  337. } else {
  338. notification_message(hid_ptt->hid->notifications, &sequence_set_red_255);
  339. }
  340. },
  341. true);
  342. }
  343. static bool hid_ptt_input_callback(InputEvent* event, void* context) {
  344. furi_assert(context);
  345. HidPtt* hid_ptt = context;
  346. bool consumed = true;
  347. hid_ptt_process(hid_ptt, event);
  348. return consumed;
  349. }
  350. HidPtt* hid_ptt_alloc(Hid* hid) {
  351. HidPtt* hid_ptt = malloc(sizeof(HidPtt));
  352. hid_ptt->view = view_alloc();
  353. hid_ptt->hid = hid;
  354. view_set_context(hid_ptt->view, hid_ptt);
  355. view_allocate_model(hid_ptt->view, ViewModelTypeLocking, sizeof(HidPttModel));
  356. view_set_draw_callback(hid_ptt->view, hid_ptt_draw_callback);
  357. view_set_input_callback(hid_ptt->view, hid_ptt_input_callback);
  358. view_set_orientation(hid_ptt->view, ViewOrientationVerticalFlip);
  359. with_view_model(
  360. hid_ptt->view, HidPttModel * model, {
  361. model->transport = hid->transport;
  362. model->muted = true; // assume we're muted
  363. model->is_mac_os = true;
  364. }, true);
  365. return hid_ptt;
  366. }
  367. void hid_ptt_free(HidPtt* hid_ptt) {
  368. furi_assert(hid_ptt);
  369. notification_message(hid_ptt->hid->notifications, &sequence_reset_red);
  370. view_free(hid_ptt->view);
  371. free(hid_ptt);
  372. }
  373. View* hid_ptt_get_view(HidPtt* hid_ptt) {
  374. furi_assert(hid_ptt);
  375. return hid_ptt->view;
  376. }
  377. void hid_ptt_set_connected_status(HidPtt* hid_ptt, bool connected) {
  378. furi_assert(hid_ptt);
  379. with_view_model(
  380. hid_ptt->view, HidPttModel * model, { model->connected = connected; }, true);
  381. }