diff --git a/applications/system/hid_app/assets/Alt_11x7.png b/applications/system/hid_app/assets/Alt_11x7.png deleted file mode 100644 index 3e4bf320ee31..000000000000 Binary files a/applications/system/hid_app/assets/Alt_11x7.png and /dev/null differ diff --git a/applications/system/hid_app/assets/BtnFrameLeft_3x18.png b/applications/system/hid_app/assets/BtnFrameLeft_3x18.png new file mode 100644 index 000000000000..f39e89f8b777 Binary files /dev/null and b/applications/system/hid_app/assets/BtnFrameLeft_3x18.png differ diff --git a/applications/system/hid_app/assets/BtnFrameRight_2x18.png b/applications/system/hid_app/assets/BtnFrameRight_2x18.png new file mode 100644 index 000000000000..d6edbb713390 Binary files /dev/null and b/applications/system/hid_app/assets/BtnFrameRight_2x18.png differ diff --git a/applications/system/hid_app/assets/Cmd_15x7.png b/applications/system/hid_app/assets/Cmd_15x7.png deleted file mode 100644 index a63a4be747a8..000000000000 Binary files a/applications/system/hid_app/assets/Cmd_15x7.png and /dev/null differ diff --git a/applications/system/hid_app/assets/Ctrl_15x7.png b/applications/system/hid_app/assets/Ctrl_15x7.png deleted file mode 100644 index b15c249b2e89..000000000000 Binary files a/applications/system/hid_app/assets/Ctrl_15x7.png and /dev/null differ diff --git a/applications/system/hid_app/assets/Del_12x7.png b/applications/system/hid_app/assets/Del_12x7.png deleted file mode 100644 index fd6b3947f7d4..000000000000 Binary files a/applications/system/hid_app/assets/Del_12x7.png and /dev/null differ diff --git a/applications/system/hid_app/assets/Esc_14x7.png b/applications/system/hid_app/assets/Esc_14x7.png deleted file mode 100644 index 3be4691d8a3d..000000000000 Binary files a/applications/system/hid_app/assets/Esc_14x7.png and /dev/null differ diff --git a/applications/system/hid_app/assets/KB_key_Alt_17x10.png b/applications/system/hid_app/assets/KB_key_Alt_17x10.png new file mode 100644 index 000000000000..26c4f73152d4 Binary files /dev/null and b/applications/system/hid_app/assets/KB_key_Alt_17x10.png differ diff --git a/applications/system/hid_app/assets/KB_key_Cmd_17x10.png b/applications/system/hid_app/assets/KB_key_Cmd_17x10.png new file mode 100644 index 000000000000..8d87ffde65d4 Binary files /dev/null and b/applications/system/hid_app/assets/KB_key_Cmd_17x10.png differ diff --git a/applications/system/hid_app/assets/KB_key_Ctl_17x10.png b/applications/system/hid_app/assets/KB_key_Ctl_17x10.png new file mode 100644 index 000000000000..01f3157c98e4 Binary files /dev/null and b/applications/system/hid_app/assets/KB_key_Ctl_17x10.png differ diff --git a/applications/system/hid_app/assets/KB_key_Del_17x10.png b/applications/system/hid_app/assets/KB_key_Del_17x10.png new file mode 100644 index 000000000000..62bad18b5456 Binary files /dev/null and b/applications/system/hid_app/assets/KB_key_Del_17x10.png differ diff --git a/applications/system/hid_app/assets/KB_key_Esc_17x10.png b/applications/system/hid_app/assets/KB_key_Esc_17x10.png new file mode 100644 index 000000000000..7a9fdda225b3 Binary files /dev/null and b/applications/system/hid_app/assets/KB_key_Esc_17x10.png differ diff --git a/applications/system/hid_app/assets/KB_key_Tab_17x10.png b/applications/system/hid_app/assets/KB_key_Tab_17x10.png new file mode 100644 index 000000000000..d904dd4187f6 Binary files /dev/null and b/applications/system/hid_app/assets/KB_key_Tab_17x10.png differ diff --git a/applications/system/hid_app/assets/Mic_btn_8x10.png b/applications/system/hid_app/assets/Mic_btn_8x10.png new file mode 100644 index 000000000000..a08bb35dd8bc Binary files /dev/null and b/applications/system/hid_app/assets/Mic_btn_8x10.png differ diff --git a/applications/system/hid_app/assets/OutCircles_70x51.png b/applications/system/hid_app/assets/OutCircles_70x51.png new file mode 100644 index 000000000000..f34d2687a6b1 Binary files /dev/null and b/applications/system/hid_app/assets/OutCircles_70x51.png differ diff --git a/applications/system/hid_app/assets/Pause_icon_9x9.png b/applications/system/hid_app/assets/Pause_icon_9x9.png new file mode 100644 index 000000000000..fe16dc03e262 Binary files /dev/null and b/applications/system/hid_app/assets/Pause_icon_9x9.png differ diff --git a/applications/system/hid_app/assets/Pin_back_arrow_10x10.png b/applications/system/hid_app/assets/Pin_back_arrow_10x10.png new file mode 100644 index 000000000000..e7510fd5dc00 Binary files /dev/null and b/applications/system/hid_app/assets/Pin_back_arrow_10x10.png differ diff --git a/applications/system/hid_app/assets/Pin_back_arrow_rotated_8x10.png b/applications/system/hid_app/assets/Pin_back_arrow_rotated_8x10.png new file mode 100644 index 000000000000..929992022b30 Binary files /dev/null and b/applications/system/hid_app/assets/Pin_back_arrow_rotated_8x10.png differ diff --git a/applications/system/hid_app/assets/Pressed_Button_19x19.png b/applications/system/hid_app/assets/Pressed_Button_19x19.png new file mode 100644 index 000000000000..42a7dbdccf11 Binary files /dev/null and b/applications/system/hid_app/assets/Pressed_Button_19x19.png differ diff --git a/applications/system/hid_app/assets/S_DOWN_31x15.png b/applications/system/hid_app/assets/S_DOWN_31x15.png new file mode 100644 index 000000000000..eac667aa05f3 Binary files /dev/null and b/applications/system/hid_app/assets/S_DOWN_31x15.png differ diff --git a/applications/system/hid_app/assets/S_LEFT_15x31.png b/applications/system/hid_app/assets/S_LEFT_15x31.png new file mode 100644 index 000000000000..13c9f51b4ee4 Binary files /dev/null and b/applications/system/hid_app/assets/S_LEFT_15x31.png differ diff --git a/applications/system/hid_app/assets/S_RIGHT_15x31.png b/applications/system/hid_app/assets/S_RIGHT_15x31.png new file mode 100644 index 000000000000..e0ba2afd1aef Binary files /dev/null and b/applications/system/hid_app/assets/S_RIGHT_15x31.png differ diff --git a/applications/system/hid_app/assets/S_UP_31x15.png b/applications/system/hid_app/assets/S_UP_31x15.png new file mode 100644 index 000000000000..e55a0362403d Binary files /dev/null and b/applications/system/hid_app/assets/S_UP_31x15.png differ diff --git a/applications/system/hid_app/assets/Tab_15x7.png b/applications/system/hid_app/assets/Tab_15x7.png deleted file mode 100644 index 06ccccee79d0..000000000000 Binary files a/applications/system/hid_app/assets/Tab_15x7.png and /dev/null differ diff --git a/applications/system/hid_app/assets/Voldwn_6x6.png b/applications/system/hid_app/assets/Voldwn_6x6.png index d7a82a2df826..ce487b546812 100644 Binary files a/applications/system/hid_app/assets/Voldwn_6x6.png and b/applications/system/hid_app/assets/Voldwn_6x6.png differ diff --git a/applications/system/hid_app/assets/Volup_8x6.png b/applications/system/hid_app/assets/Volup_8x6.png index 4b7ec66d6517..ee9045f7fde3 100644 Binary files a/applications/system/hid_app/assets/Volup_8x6.png and b/applications/system/hid_app/assets/Volup_8x6.png differ diff --git a/applications/system/hid_app/hid.c b/applications/system/hid_app/hid.c index a42fc6091783..0dd560a97587 100644 --- a/applications/system/hid_app/hid.c +++ b/applications/system/hid_app/hid.c @@ -9,11 +9,14 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexKeynote, HidSubmenuIndexKeynoteVertical, HidSubmenuIndexKeyboard, + HidSubmenuIndexNumpad, HidSubmenuIndexMedia, - HidSubmenuIndexTikTok, + HidSubmenuIndexMovie, + HidSubmenuIndexTikShorts, HidSubmenuIndexMouse, HidSubmenuIndexMouseClicker, HidSubmenuIndexMouseJiggler, + HidSubmenuIndexPtt, }; static void hid_submenu_callback(void* context, uint32_t index) { @@ -30,21 +33,30 @@ static void hid_submenu_callback(void* context, uint32_t index) { } else if(index == HidSubmenuIndexKeyboard) { app->view_id = HidViewKeyboard; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeyboard); + } else if(index == HidSubmenuIndexNumpad) { + app->view_id = HidViewNumpad; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewNumpad); } else if(index == HidSubmenuIndexMedia) { app->view_id = HidViewMedia; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMedia); + } else if(index == HidSubmenuIndexMovie) { + app->view_id = HidViewMovie; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMovie); } else if(index == HidSubmenuIndexMouse) { app->view_id = HidViewMouse; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouse); - } else if(index == HidSubmenuIndexTikTok) { - app->view_id = BtHidViewTikTok; - view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikTok); + } else if(index == HidSubmenuIndexTikShorts) { + app->view_id = BtHidViewTikShorts; + view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikShorts); } else if(index == HidSubmenuIndexMouseClicker) { app->view_id = HidViewMouseClicker; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseClicker); } else if(index == HidSubmenuIndexMouseJiggler) { app->view_id = HidViewMouseJiggler; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler); + } else if(index == HidSubmenuIndexPtt) { + app->view_id = HidViewPtt; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewPtt); } } @@ -61,11 +73,14 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con } hid_keynote_set_connected_status(hid->hid_keynote, connected); hid_keyboard_set_connected_status(hid->hid_keyboard, connected); + hid_numpad_set_connected_status(hid->hid_numpad, connected); hid_media_set_connected_status(hid->hid_media, connected); + hid_movie_set_connected_status(hid->hid_movie, connected); hid_mouse_set_connected_status(hid->hid_mouse, connected); hid_mouse_clicker_set_connected_status(hid->hid_mouse_clicker, connected); hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected); - hid_tiktok_set_connected_status(hid->hid_tiktok, connected); + hid_ptt_set_connected_status(hid->hid_ptt, connected); + hid_tikshorts_set_connected_status(hid->hid_tikshorts, connected); } static void hid_dialog_callback(DialogExResult result, void* context) { @@ -80,6 +95,11 @@ static void hid_dialog_callback(DialogExResult result, void* context) { } } +static uint32_t hid_menu_view(void* context) { + UNUSED(context); + return HidViewSubmenu; +} + static uint32_t hid_exit_confirm_view(void* context) { UNUSED(context); return HidViewExitConfirm; @@ -119,15 +139,19 @@ Hid* hid_alloc(HidTransport transport) { app); submenu_add_item( app->device_type_submenu, "Keyboard", HidSubmenuIndexKeyboard, hid_submenu_callback, app); + submenu_add_item( + app->device_type_submenu, "Numpad", HidSubmenuIndexNumpad, hid_submenu_callback, app); submenu_add_item( app->device_type_submenu, "Media", HidSubmenuIndexMedia, hid_submenu_callback, app); + submenu_add_item( + app->device_type_submenu, "Movie", HidSubmenuIndexMovie, hid_submenu_callback, app); submenu_add_item( app->device_type_submenu, "Mouse", HidSubmenuIndexMouse, hid_submenu_callback, app); if(app->transport == HidTransportBle) { submenu_add_item( app->device_type_submenu, - "TikTok Controller", - HidSubmenuIndexTikTok, + "TikTok / YT Shorts", + HidSubmenuIndexTikShorts, hid_submenu_callback, app); } @@ -143,6 +167,8 @@ Hid* hid_alloc(HidTransport transport) { HidSubmenuIndexMouseJiggler, hid_submenu_callback, app); + submenu_add_item( + app->device_type_submenu, "PTT", HidSubmenuIndexPtt, hid_submenu_callback, app); view_set_previous_callback(submenu_get_view(app->device_type_submenu), hid_exit); view_dispatcher_add_view( app->view_dispatcher, HidViewSubmenu, submenu_get_view(app->device_type_submenu)); @@ -167,27 +193,39 @@ Hid* hid_app_alloc_view(void* context) { // Keynote view app->hid_keynote = hid_keynote_alloc(app); - view_set_previous_callback(hid_keynote_get_view(app->hid_keynote), hid_exit_confirm_view); + view_set_previous_callback(hid_keynote_get_view(app->hid_keynote), hid_menu_view); view_dispatcher_add_view( app->view_dispatcher, HidViewKeynote, hid_keynote_get_view(app->hid_keynote)); // Keyboard view app->hid_keyboard = hid_keyboard_alloc(app); - view_set_previous_callback(hid_keyboard_get_view(app->hid_keyboard), hid_exit_confirm_view); + view_set_previous_callback(hid_keyboard_get_view(app->hid_keyboard), hid_menu_view); view_dispatcher_add_view( app->view_dispatcher, HidViewKeyboard, hid_keyboard_get_view(app->hid_keyboard)); + //Numpad keyboard view + app->hid_numpad = hid_numpad_alloc(app); + view_set_previous_callback(hid_numpad_get_view(app->hid_numpad), hid_menu_view); + view_dispatcher_add_view( + app->view_dispatcher, HidViewNumpad, hid_numpad_get_view(app->hid_numpad)); + // Media view app->hid_media = hid_media_alloc(app); - view_set_previous_callback(hid_media_get_view(app->hid_media), hid_exit_confirm_view); + view_set_previous_callback(hid_media_get_view(app->hid_media), hid_menu_view); view_dispatcher_add_view( app->view_dispatcher, HidViewMedia, hid_media_get_view(app->hid_media)); + + // Movie view + app->hid_movie = hid_movie_alloc(app); + view_set_previous_callback(hid_movie_get_view(app->hid_movie), hid_menu_view); + view_dispatcher_add_view( + app->view_dispatcher, HidViewMovie, hid_movie_get_view(app->hid_movie)); - // TikTok view - app->hid_tiktok = hid_tiktok_alloc(app); - view_set_previous_callback(hid_tiktok_get_view(app->hid_tiktok), hid_exit_confirm_view); + // TikTok / YT Shorts view + app->hid_tikshorts = hid_tikshorts_alloc(app); + view_set_previous_callback(hid_tikshorts_get_view(app->hid_tikshorts), hid_exit_confirm_view); view_dispatcher_add_view( - app->view_dispatcher, BtHidViewTikTok, hid_tiktok_get_view(app->hid_tiktok)); + app->view_dispatcher, BtHidViewTikShorts, hid_tikshorts_get_view(app->hid_tikshorts)); // Mouse view app->hid_mouse = hid_mouse_alloc(app); @@ -198,7 +236,7 @@ Hid* hid_app_alloc_view(void* context) { // Mouse clicker view app->hid_mouse_clicker = hid_mouse_clicker_alloc(app); view_set_previous_callback( - hid_mouse_clicker_get_view(app->hid_mouse_clicker), hid_exit_confirm_view); + hid_mouse_clicker_get_view(app->hid_mouse_clicker), hid_menu_view); view_dispatcher_add_view( app->view_dispatcher, HidViewMouseClicker, @@ -207,12 +245,18 @@ Hid* hid_app_alloc_view(void* context) { // Mouse jiggler view app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app); view_set_previous_callback( - hid_mouse_jiggler_get_view(app->hid_mouse_jiggler), hid_exit_confirm_view); + hid_mouse_jiggler_get_view(app->hid_mouse_jiggler), hid_menu_view); view_dispatcher_add_view( app->view_dispatcher, HidViewMouseJiggler, hid_mouse_jiggler_get_view(app->hid_mouse_jiggler)); + // Ptt view + app->hid_ptt = hid_ptt_alloc(app); + view_set_previous_callback(hid_ptt_get_view(app->hid_ptt), hid_menu_view); + view_dispatcher_add_view( + app->view_dispatcher, HidViewPtt, hid_ptt_get_view(app->hid_ptt)); + return app; } @@ -233,16 +277,22 @@ void hid_free(Hid* app) { hid_keynote_free(app->hid_keynote); view_dispatcher_remove_view(app->view_dispatcher, HidViewKeyboard); hid_keyboard_free(app->hid_keyboard); + view_dispatcher_remove_view(app->view_dispatcher, HidViewNumpad); + hid_numpad_free(app->hid_numpad); view_dispatcher_remove_view(app->view_dispatcher, HidViewMedia); hid_media_free(app->hid_media); + view_dispatcher_remove_view(app->view_dispatcher, HidViewMovie); + hid_movie_free(app->hid_movie); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouse); hid_mouse_free(app->hid_mouse); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseClicker); hid_mouse_clicker_free(app->hid_mouse_clicker); view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseJiggler); hid_mouse_jiggler_free(app->hid_mouse_jiggler); - view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok); - hid_tiktok_free(app->hid_tiktok); + view_dispatcher_remove_view(app->view_dispatcher, HidViewPtt); + hid_ptt_free(app->hid_ptt); + view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikShorts); + hid_tikshorts_free(app->hid_tikshorts); view_dispatcher_free(app->view_dispatcher); // Close records diff --git a/applications/system/hid_app/hid.h b/applications/system/hid_app/hid.h index 49d8b4e045d3..3570c38c8fad 100644 --- a/applications/system/hid_app/hid.h +++ b/applications/system/hid_app/hid.h @@ -18,11 +18,14 @@ #include #include "views/hid_keynote.h" #include "views/hid_keyboard.h" +#include "views/hid_numpad.h" #include "views/hid_media.h" +#include "views/hid_movie.h" #include "views/hid_mouse.h" #include "views/hid_mouse_clicker.h" #include "views/hid_mouse_jiggler.h" -#include "views/hid_tiktok.h" +#include "views/hid_tikshorts.h" +#include "views/hid_ptt.h" #define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys" @@ -42,11 +45,14 @@ struct Hid { DialogEx* dialog; HidKeynote* hid_keynote; HidKeyboard* hid_keyboard; + HidNumpad* hid_numpad; HidMedia* hid_media; + HidMovie* hid_movie; HidMouse* hid_mouse; HidMouseClicker* hid_mouse_clicker; HidMouseJiggler* hid_mouse_jiggler; - HidTikTok* hid_tiktok; + HidTikShorts* hid_tikshorts; + HidPtt* hid_ptt; HidTransport transport; uint32_t view_id; @@ -64,4 +70,4 @@ void hid_hal_mouse_move(Hid* instance, int8_t dx, int8_t dy); void hid_hal_mouse_scroll(Hid* instance, int8_t delta); void hid_hal_mouse_press(Hid* instance, uint16_t event); void hid_hal_mouse_release(Hid* instance, uint16_t event); -void hid_hal_mouse_release_all(Hid* instance); \ No newline at end of file +void hid_hal_mouse_release_all(Hid* instance); diff --git a/applications/system/hid_app/views.h b/applications/system/hid_app/views.h index 1bea3355e0d1..7db43d6a2ebf 100644 --- a/applications/system/hid_app/views.h +++ b/applications/system/hid_app/views.h @@ -2,10 +2,13 @@ typedef enum { HidViewSubmenu, HidViewKeynote, HidViewKeyboard, + HidViewNumpad, HidViewMedia, + HidViewMovie, HidViewMouse, HidViewMouseClicker, HidViewMouseJiggler, - BtHidViewTikTok, + BtHidViewTikShorts, + HidViewPtt, HidViewExitConfirm, -} HidView; \ No newline at end of file +} HidView; diff --git a/applications/system/hid_app/views/hid_keyboard.c b/applications/system/hid_app/views/hid_keyboard.c index 17ff754f52c7..1ce0285b2d60 100644 --- a/applications/system/hid_app/views/hid_keyboard.c +++ b/applications/system/hid_app/views/hid_keyboard.c @@ -140,18 +140,18 @@ const HidKeyboardKey hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { {.width = 1, .icon = &I_ButtonRight_4x7, .value = HID_KEYBOARD_RIGHT_ARROW}, }, { - {.width = 2, .icon = &I_Ctrl_15x7, .value = HID_KEYBOARD_L_CTRL}, - {.width = 0, .value = HID_KEYBOARD_L_CTRL}, - {.width = 2, .icon = &I_Alt_11x7, .value = HID_KEYBOARD_L_ALT}, - {.width = 0, .value = HID_KEYBOARD_L_ALT}, - {.width = 2, .icon = &I_Cmd_15x7, .value = HID_KEYBOARD_L_GUI}, - {.width = 0, .value = HID_KEYBOARD_L_GUI}, - {.width = 2, .icon = &I_Tab_15x7, .value = HID_KEYBOARD_TAB}, - {.width = 0, .value = HID_KEYBOARD_TAB}, - {.width = 2, .icon = &I_Esc_14x7, .value = HID_KEYBOARD_ESCAPE}, - {.width = 0, .value = HID_KEYBOARD_ESCAPE}, - {.width = 2, .icon = &I_Del_12x7, .value = HID_KEYBOARD_DELETE_FORWARD}, - {.width = 0, .value = HID_KEYBOARD_DELETE_FORWARD}, + {.width = 2, .icon = &I_KB_key_Ctl_17x10, .value = HID_KEYBOARD_L_CTRL}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_CTRL}, + {.width = 2, .icon = &I_KB_key_Alt_17x10, .value = HID_KEYBOARD_L_ALT}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_ALT}, + {.width = 2, .icon = &I_KB_key_Cmd_17x10, .value = HID_KEYBOARD_L_GUI}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_GUI}, + {.width = 2, .icon = &I_KB_key_Tab_17x10, .value = HID_KEYBOARD_TAB}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_TAB}, + {.width = 2, .icon = &I_KB_key_Esc_17x10, .value = HID_KEYBOARD_ESCAPE}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_ESCAPE}, + {.width = 2, .icon = &I_KB_key_Del_17x10, .value = HID_KEYBOARD_DELETE_FORWARD}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_DELETE_FORWARD}, }, }; diff --git a/applications/system/hid_app/views/hid_keynote.c b/applications/system/hid_app/views/hid_keynote.c index 543363bf67b7..7d0e125d77a6 100644 --- a/applications/system/hid_app/views/hid_keynote.c +++ b/applications/system/hid_app/views/hid_keynote.c @@ -116,16 +116,16 @@ static void hid_keynote_draw_vertical_callback(Canvas* canvas, void* context) { HidKeynoteModel* model = context; // Header + canvas_set_font(canvas, FontPrimary); if(model->transport == HidTransportBle) { if(model->connected) { canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); } else { canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); } - canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 20, 3, AlignLeft, AlignTop, "Keynote"); } else { - canvas_set_font(canvas, FontPrimary); elements_multiline_text_aligned(canvas, 12, 3, AlignLeft, AlignTop, "Keynote"); } diff --git a/applications/system/hid_app/views/hid_media.c b/applications/system/hid_app/views/hid_media.c index 468529d56a85..2fc0cfb1a24f 100644 --- a/applications/system/hid_app/views/hid_media.c +++ b/applications/system/hid_app/views/hid_media.c @@ -21,6 +21,7 @@ typedef struct { bool down_pressed; bool ok_pressed; bool connected; + bool back_pressed; HidTransport transport; } HidMediaModel; @@ -55,61 +56,74 @@ static void hid_media_draw_callback(Canvas* canvas, void* context) { canvas_set_font(canvas, FontSecondary); // Keypad circles - canvas_draw_icon(canvas, 76, 8, &I_Circles_47x47); + canvas_draw_icon(canvas, 58, 3, &I_OutCircles_70x51); // Up if(model->up_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 68, 6, &I_S_UP_31x15); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 96, 12, &I_Volup_8x6); + canvas_draw_icon(canvas, 79, 9, &I_Volup_8x6); canvas_set_color(canvas, ColorBlack); // Down if(model->down_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 68, 36, &I_S_DOWN_31x15); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 96, 45, &I_Voldwn_6x6); + canvas_draw_icon(canvas, 80, 41, &I_Voldwn_6x6); canvas_set_color(canvas, ColorBlack); // Left if(model->left_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 61, 13, &I_S_LEFT_15x31); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - hid_media_draw_arrow(canvas, 82, 31, CanvasDirectionRightToLeft); - hid_media_draw_arrow(canvas, 86, 31, CanvasDirectionRightToLeft); + hid_media_draw_arrow(canvas, 67, 28, CanvasDirectionRightToLeft); + hid_media_draw_arrow(canvas, 70, 28, CanvasDirectionRightToLeft); + canvas_draw_line(canvas, 64, 26, 64, 30); canvas_set_color(canvas, ColorBlack); // Right if(model->right_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT_15x31); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - hid_media_draw_arrow(canvas, 112, 31, CanvasDirectionLeftToRight); - hid_media_draw_arrow(canvas, 116, 31, CanvasDirectionLeftToRight); + hid_media_draw_arrow(canvas, 96, 28, CanvasDirectionLeftToRight); + hid_media_draw_arrow(canvas, 99, 28, CanvasDirectionLeftToRight); + canvas_draw_line(canvas, 102, 26, 102, 30); canvas_set_color(canvas, ColorBlack); // Ok if(model->ok_pressed) { - canvas_draw_icon(canvas, 93, 25, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19); + canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - hid_media_draw_arrow(canvas, 96, 31, CanvasDirectionLeftToRight); - canvas_draw_line(canvas, 100, 29, 100, 33); - canvas_draw_line(canvas, 102, 29, 102, 33); + hid_media_draw_arrow(canvas, 80, 28, CanvasDirectionLeftToRight); + canvas_draw_line(canvas, 84, 26, 84, 30); + canvas_draw_line(canvas, 86, 26, 86, 30); canvas_set_color(canvas, ColorBlack); // Exit + if(model->back_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 111, 38, &I_Pin_back_arrow_10x10); + canvas_set_color(canvas, ColorBlack); + canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); canvas_set_font(canvas, FontSecondary); elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); @@ -135,6 +149,8 @@ static void hid_media_process_press(HidMedia* hid_media, InputEvent* event) { } else if(event->key == InputKeyOk) { model->ok_pressed = true; hid_hal_consumer_key_press(hid_media->hid, HID_CONSUMER_PLAY_PAUSE); + } else if(event->key == InputKeyBack) { + model->back_pressed = true; } }, true); @@ -160,6 +176,8 @@ static void hid_media_process_release(HidMedia* hid_media, InputEvent* event) { } else if(event->key == InputKeyOk) { model->ok_pressed = false; hid_hal_consumer_key_release(hid_media->hid, HID_CONSUMER_PLAY_PAUSE); + } else if(event->key == InputKeyBack) { + model->back_pressed = false; } }, true); @@ -176,12 +194,7 @@ static bool hid_media_input_callback(InputEvent* event, void* context) { } else if(event->type == InputTypeRelease) { hid_media_process_release(hid_media, event); consumed = true; - } else if(event->type == InputTypeShort) { - if(event->key == InputKeyBack) { - hid_hal_consumer_key_release_all(hid_media->hid); - } } - return consumed; } diff --git a/applications/system/hid_app/views/hid_mouse.c b/applications/system/hid_app/views/hid_mouse.c index 30a9d9d06358..3ae7c8145442 100644 --- a/applications/system/hid_app/views/hid_mouse.c +++ b/applications/system/hid_app/views/hid_mouse.c @@ -20,6 +20,7 @@ typedef struct { bool left_mouse_held; bool right_mouse_pressed; bool connected; + uint8_t acceleration; HidTransport transport; } HidMouseModel; @@ -49,61 +50,67 @@ static void hid_mouse_draw_callback(Canvas* canvas, void* context) { } // Keypad circles - canvas_draw_icon(canvas, 64, 8, &I_Circles_47x47); + canvas_draw_icon(canvas, 58, 3, &I_OutCircles_70x51); // Up if(model->up_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 81, 9, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 68, 6, &I_S_UP_31x15); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up_7x9); + canvas_draw_icon(canvas, 80, 8, &I_Pin_arrow_up_7x9); canvas_set_color(canvas, ColorBlack); // Down if(model->down_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 81, 41, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 68, 36, &I_S_DOWN_31x15); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 84, 43, &I_Pin_arrow_down_7x9); + canvas_draw_icon(canvas, 80, 40, &I_Pin_arrow_down_7x9); canvas_set_color(canvas, ColorBlack); // Left if(model->left_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 65, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 61, 13, &I_S_LEFT_15x31); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 67, 28, &I_Pin_arrow_left_9x7); + canvas_draw_icon(canvas, 63, 25, &I_Pin_arrow_left_9x7); canvas_set_color(canvas, ColorBlack); // Right if(model->right_pressed) { canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 97, 25, &I_Pressed_Button_13x13); + canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT_15x31); canvas_set_bitmap_mode(canvas, 0); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 99, 28, &I_Pin_arrow_right_9x7); + canvas_draw_icon(canvas, 95, 25, &I_Pin_arrow_right_9x7); canvas_set_color(canvas, ColorBlack); // Ok if(model->left_mouse_pressed) { - canvas_draw_icon(canvas, 81, 25, &I_Ok_btn_pressed_13x13); - } else { - canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9); + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); } + canvas_draw_icon(canvas, 79, 24, &I_Left_mouse_icon_9x9); + canvas_set_color(canvas, ColorBlack); // Back if(model->right_mouse_pressed) { - canvas_draw_icon(canvas, 108, 48, &I_Ok_btn_pressed_13x13); - } else { - canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9); + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); } + canvas_draw_icon(canvas, 112, 38, &I_Right_mouse_icon_9x9); + canvas_set_color(canvas, ColorBlack); } static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) { @@ -111,6 +118,11 @@ static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) { hid_mouse->view, HidMouseModel * model, { + model->acceleration = (event->type == InputTypePress) ? 1 : + (event->type == InputTypeRelease) ? 0 : + (model->acceleration >= 20) ? 20 : + model->acceleration + 1; + if(event->key == InputKeyBack) { if(event->type == InputTypeShort) { hid_hal_mouse_press(hid_mouse->hid, HID_MOUSE_BTN_RIGHT); @@ -142,7 +154,8 @@ static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) { model->right_pressed = true; hid_hal_mouse_move(hid_mouse->hid, MOUSE_MOVE_SHORT, 0); } else if(event->type == InputTypeRepeat) { - hid_hal_mouse_move(hid_mouse->hid, MOUSE_MOVE_LONG, 0); + for(uint8_t i = model->acceleration; i > 1; i -= 2) + hid_hal_mouse_move(hid_mouse->hid, MOUSE_MOVE_LONG, 0); } else if(event->type == InputTypeRelease) { model->right_pressed = false; } @@ -151,7 +164,8 @@ static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) { model->left_pressed = true; hid_hal_mouse_move(hid_mouse->hid, -MOUSE_MOVE_SHORT, 0); } else if(event->type == InputTypeRepeat) { - hid_hal_mouse_move(hid_mouse->hid, -MOUSE_MOVE_LONG, 0); + for(uint8_t i = model->acceleration; i > 1; i -= 2) + hid_hal_mouse_move(hid_mouse->hid, -MOUSE_MOVE_LONG, 0); } else if(event->type == InputTypeRelease) { model->left_pressed = false; } @@ -160,7 +174,9 @@ static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) { model->down_pressed = true; hid_hal_mouse_move(hid_mouse->hid, 0, MOUSE_MOVE_SHORT); } else if(event->type == InputTypeRepeat) { - hid_hal_mouse_move(hid_mouse->hid, 0, MOUSE_MOVE_LONG); + for(uint8_t i = model->acceleration; i > 1; i -= 2) + hid_hal_mouse_move(hid_mouse->hid, 0, MOUSE_MOVE_LONG); + } else if(event->type == InputTypeRelease) { model->down_pressed = false; } @@ -169,7 +185,8 @@ static void hid_mouse_process(HidMouse* hid_mouse, InputEvent* event) { model->up_pressed = true; hid_hal_mouse_move(hid_mouse->hid, 0, -MOUSE_MOVE_SHORT); } else if(event->type == InputTypeRepeat) { - hid_hal_mouse_move(hid_mouse->hid, 0, -MOUSE_MOVE_LONG); + for(uint8_t i = model->acceleration; i > 1; i -= 2) + hid_hal_mouse_move(hid_mouse->hid, 0, -MOUSE_MOVE_LONG); } else if(event->type == InputTypeRelease) { model->up_pressed = false; } diff --git a/applications/system/hid_app/views/hid_mouse_jiggler.c b/applications/system/hid_app/views/hid_mouse_jiggler.c index 15547eb26b58..3da969aae287 100644 --- a/applications/system/hid_app/views/hid_mouse_jiggler.c +++ b/applications/system/hid_app/views/hid_mouse_jiggler.c @@ -15,10 +15,13 @@ struct HidMouseJiggler { typedef struct { bool connected; bool running; + int interval_idx; uint8_t counter; HidTransport transport; } HidMouseJigglerModel; +const int intervals[6] = {500, 2000, 5000, 10000, 30000, 60000}; + static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { furi_assert(context); HidMouseJigglerModel* model = context; @@ -33,29 +36,39 @@ static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) { } canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Jiggler"); + elements_multiline_text_aligned(canvas, 17, 2, AlignLeft, AlignTop, "Mouse Jiggler"); + + // Timeout + elements_multiline_text(canvas, AlignLeft, 26, "Interval (ms):"); + canvas_set_font(canvas, FontSecondary); + if(model->interval_idx != 0) canvas_draw_icon(canvas, 74, 19, &I_ButtonLeft_4x7); + if(model->interval_idx != (int)COUNT_OF(intervals) - 1) + canvas_draw_icon(canvas, 80, 19, &I_ButtonRight_4x7); + FuriString* interval_str = furi_string_alloc_printf("%d", intervals[model->interval_idx]); + elements_multiline_text(canvas, 91, 26, furi_string_get_cstr(interval_str)); + furi_string_free(interval_str); canvas_set_font(canvas, FontPrimary); - elements_multiline_text(canvas, AlignLeft, 35, "Press Start\nto jiggle"); + elements_multiline_text(canvas, AlignLeft, 40, "Press Start\nto jiggle"); canvas_set_font(canvas, FontSecondary); // Ok - canvas_draw_icon(canvas, 63, 25, &I_Space_65x18); + canvas_draw_icon(canvas, 63, 30, &I_Space_65x18); if(model->running) { - elements_slightly_rounded_box(canvas, 66, 27, 60, 13); + elements_slightly_rounded_box(canvas, 66, 32, 60, 13); canvas_set_color(canvas, ColorWhite); } - canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9); + canvas_draw_icon(canvas, 74, 34, &I_Ok_btn_9x9); if(model->running) { - elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Stop"); + elements_multiline_text_aligned(canvas, 91, 41, AlignLeft, AlignBottom, "Stop"); } else { - elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Start"); + elements_multiline_text_aligned(canvas, 91, 41, AlignLeft, AlignBottom, "Start"); } canvas_set_color(canvas, ColorBlack); // Back - canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8); - elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Quit"); + canvas_draw_icon(canvas, 74, 54, &I_Pin_back_arrow_10x8); + elements_multiline_text_aligned(canvas, 91, 62, AlignLeft, AlignBottom, "Quit"); } static void hid_mouse_jiggler_timer_callback(void* context) { @@ -69,20 +82,13 @@ static void hid_mouse_jiggler_timer_callback(void* context) { model->counter++; hid_hal_mouse_move( hid_mouse_jiggler->hid, - (model->counter % 2 == 0) ? MOUSE_MOVE_SHORT : -MOUSE_MOVE_SHORT, + (model->counter % 2 == 0) ? MOUSE_MOVE_TINY : -MOUSE_MOVE_TINY, 0); } }, false); } -static void hid_mouse_jiggler_enter_callback(void* context) { - furi_assert(context); - HidMouseJiggler* hid_mouse_jiggler = context; - - furi_timer_start(hid_mouse_jiggler->timer, 500); -} - static void hid_mouse_jiggler_exit_callback(void* context) { furi_assert(context); HidMouseJiggler* hid_mouse_jiggler = context; @@ -95,14 +101,30 @@ static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) { bool consumed = false; - if(event->type == InputTypeShort && event->key == InputKeyOk) { - with_view_model( - hid_mouse_jiggler->view, - HidMouseJigglerModel * model, - { model->running = !model->running; }, - true); - consumed = true; - } + with_view_model( + hid_mouse_jiggler->view, + HidMouseJigglerModel * model, + { + if(event->type == InputTypePress && event->key == InputKeyOk) { + model->running = !model->running; + if(model->running) { + furi_timer_stop(hid_mouse_jiggler->timer); + furi_timer_start(hid_mouse_jiggler->timer, intervals[model->interval_idx]); + }; + consumed = true; + } + if(event->type == InputTypePress && event->key == InputKeyRight && !model->running && + model->interval_idx < (int)COUNT_OF(intervals) - 1) { + model->interval_idx++; + consumed = true; + } + if(event->type == InputTypePress && event->key == InputKeyLeft && !model->running && + model->interval_idx > 0) { + model->interval_idx--; + consumed = true; + } + }, + true); return consumed; } @@ -116,7 +138,6 @@ HidMouseJiggler* hid_mouse_jiggler_alloc(Hid* hid) { hid_mouse_jiggler->view, ViewModelTypeLocking, sizeof(HidMouseJigglerModel)); view_set_draw_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_draw_callback); view_set_input_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_input_callback); - view_set_enter_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_enter_callback); view_set_exit_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_exit_callback); hid_mouse_jiggler->hid = hid; @@ -127,7 +148,10 @@ HidMouseJiggler* hid_mouse_jiggler_alloc(Hid* hid) { with_view_model( hid_mouse_jiggler->view, HidMouseJigglerModel * model, - { model->transport = hid->transport; }, + { + model->transport = hid->transport; + model->interval_idx = 2; + }, true); return hid_mouse_jiggler; diff --git a/applications/system/hid_app/views/hid_mouse_jiggler.h b/applications/system/hid_app/views/hid_mouse_jiggler.h index 0813b4351e19..c1f77251ecb9 100644 --- a/applications/system/hid_app/views/hid_mouse_jiggler.h +++ b/applications/system/hid_app/views/hid_mouse_jiggler.h @@ -2,8 +2,7 @@ #include -#define MOUSE_MOVE_SHORT 5 -#define MOUSE_MOVE_LONG 20 +#define MOUSE_MOVE_TINY 1 typedef struct Hid Hid; typedef struct HidMouseJiggler HidMouseJiggler; diff --git a/applications/system/hid_app/views/hid_movie.c b/applications/system/hid_app/views/hid_movie.c new file mode 100644 index 000000000000..866a4c6266cf --- /dev/null +++ b/applications/system/hid_app/views/hid_movie.c @@ -0,0 +1,229 @@ +#include "hid_movie.h" +#include +#include +#include +#include +#include "../hid.h" + +#include "hid_icons.h" + +#define TAG "HidMovie" + +struct HidMovie { + View* view; + Hid* hid; +}; + +typedef struct { + bool left_pressed; + bool up_pressed; + bool right_pressed; + bool down_pressed; + bool ok_pressed; + bool connected; + bool back_pressed; + HidTransport transport; +} HidMovieModel; + +static void hid_movie_draw_arrow(Canvas* canvas, uint8_t x, uint8_t y, CanvasDirection dir) { + canvas_draw_triangle(canvas, x, y, 5, 3, dir); + if(dir == CanvasDirectionBottomToTop) { + canvas_draw_dot(canvas, x, y - 1); + } else if(dir == CanvasDirectionTopToBottom) { + canvas_draw_dot(canvas, x, y + 1); + } else if(dir == CanvasDirectionRightToLeft) { + canvas_draw_dot(canvas, x - 1, y); + } else if(dir == CanvasDirectionLeftToRight) { + canvas_draw_dot(canvas, x + 1, y); + } +} + +static void hid_movie_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidMovieModel* model = context; + + // Header + if(model->transport == HidTransportBle) { + if(model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + } + } + + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Movie"); + canvas_set_font(canvas, FontSecondary); + + // Keypad circles + canvas_draw_icon(canvas, 58, 3, &I_OutCircles_70x51); + + // Up + if(model->up_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 68, 6, &I_S_UP_31x15); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 79, 9, &I_Volup_8x6); + canvas_set_color(canvas, ColorBlack); + + // Down + if(model->down_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 68, 36, &I_S_DOWN_31x15); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 80, 41, &I_Voldwn_6x6); + canvas_set_color(canvas, ColorBlack); + + // Left + if(model->left_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 61, 13, &I_S_LEFT_15x31); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + hid_movie_draw_arrow(canvas, 65, 28, CanvasDirectionRightToLeft); + hid_movie_draw_arrow(canvas, 70, 28, CanvasDirectionRightToLeft); + canvas_set_color(canvas, ColorBlack); + + // Right + if(model->right_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT_15x31); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + hid_movie_draw_arrow(canvas, 96, 28, CanvasDirectionLeftToRight); + hid_movie_draw_arrow(canvas, 101, 28, CanvasDirectionLeftToRight); + canvas_set_color(canvas, ColorBlack); + + // Ok + if(model->ok_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + hid_movie_draw_arrow(canvas, 80, 28, CanvasDirectionLeftToRight); + canvas_draw_line(canvas, 84, 26, 84, 30); + canvas_draw_line(canvas, 86, 26, 86, 30); + canvas_set_color(canvas, ColorBlack); + + // Exit + if(model->back_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 111, 38, &I_Pin_back_arrow_10x10); + canvas_set_color(canvas, ColorBlack); + + canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); +} + +static void hid_movie_process_press(HidMovie* hid_movie, InputEvent* event) { + with_view_model( + hid_movie->view, + HidMovieModel * model, + { + if(event->key == InputKeyUp) { + model->up_pressed = true; + hid_hal_consumer_key_press(hid_movie->hid, HID_CONSUMER_VOLUME_INCREMENT); + } else if(event->key == InputKeyDown) { + model->down_pressed = true; + hid_hal_consumer_key_press(hid_movie->hid, HID_CONSUMER_VOLUME_DECREMENT); + } else if(event->key == InputKeyLeft) { + model->left_pressed = true; + hid_hal_keyboard_press(hid_movie->hid, HID_KEYBOARD_LEFT_ARROW); + } else if(event->key == InputKeyRight) { + model->right_pressed = true; + hid_hal_keyboard_press(hid_movie->hid, HID_KEYBOARD_RIGHT_ARROW); + } else if(event->key == InputKeyOk) { + model->ok_pressed = true; + hid_hal_consumer_key_press(hid_movie->hid, HID_CONSUMER_PLAY_PAUSE); + } else if(event->key == InputKeyBack) { + model->back_pressed = true; + } + }, + true); +} + +static void hid_movie_process_release(HidMovie* hid_movie, InputEvent* event) { + with_view_model( + hid_movie->view, + HidMovieModel * model, + { + if(event->key == InputKeyUp) { + model->up_pressed = false; + hid_hal_consumer_key_release(hid_movie->hid, HID_CONSUMER_VOLUME_INCREMENT); + } else if(event->key == InputKeyDown) { + model->down_pressed = false; + hid_hal_consumer_key_release(hid_movie->hid, HID_CONSUMER_VOLUME_DECREMENT); + } else if(event->key == InputKeyLeft) { + model->left_pressed = false; + hid_hal_keyboard_release(hid_movie->hid, HID_KEYBOARD_LEFT_ARROW); + } else if(event->key == InputKeyRight) { + model->right_pressed = false; + hid_hal_keyboard_release(hid_movie->hid, HID_KEYBOARD_RIGHT_ARROW); + } else if(event->key == InputKeyOk) { + model->ok_pressed = false; + hid_hal_consumer_key_release(hid_movie->hid, HID_CONSUMER_PLAY_PAUSE); + } else if(event->key == InputKeyBack) { + model->back_pressed = false; + } + }, + true); +} + +static bool hid_movie_input_callback(InputEvent* event, void* context) { + furi_assert(context); + HidMovie* hid_movie = context; + bool consumed = false; + + if(event->type == InputTypePress) { + hid_movie_process_press(hid_movie, event); + consumed = true; + } else if(event->type == InputTypeRelease) { + hid_movie_process_release(hid_movie, event); + consumed = true; + } + return consumed; +} + +HidMovie* hid_movie_alloc(Hid* hid) { + HidMovie* hid_movie = malloc(sizeof(HidMovie)); + hid_movie->view = view_alloc(); + hid_movie->hid = hid; + view_set_context(hid_movie->view, hid_movie); + view_allocate_model(hid_movie->view, ViewModelTypeLocking, sizeof(HidMovieModel)); + view_set_draw_callback(hid_movie->view, hid_movie_draw_callback); + view_set_input_callback(hid_movie->view, hid_movie_input_callback); + + with_view_model( + hid_movie->view, HidMovieModel * model, { model->transport = hid->transport; }, true); + + return hid_movie; +} + +void hid_movie_free(HidMovie* hid_movie) { + furi_assert(hid_movie); + view_free(hid_movie->view); + free(hid_movie); +} + +View* hid_movie_get_view(HidMovie* hid_movie) { + furi_assert(hid_movie); + return hid_movie->view; +} + +void hid_movie_set_connected_status(HidMovie* hid_movie, bool connected) { + furi_assert(hid_movie); + with_view_model( + hid_movie->view, HidMovieModel * model, { model->connected = connected; }, true); +} diff --git a/applications/system/hid_app/views/hid_movie.h b/applications/system/hid_app/views/hid_movie.h new file mode 100644 index 000000000000..52dedc9886f4 --- /dev/null +++ b/applications/system/hid_app/views/hid_movie.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidMovie HidMovie; + +HidMovie* hid_movie_alloc(Hid* bt_hid); + +void hid_movie_free(HidMovie* hid_movie); + +View* hid_movie_get_view(HidMovie* hid_movie); + +void hid_movie_set_connected_status(HidMovie* hid_movie, bool connected); diff --git a/applications/system/hid_app/views/hid_numpad.c b/applications/system/hid_app/views/hid_numpad.c new file mode 100644 index 000000000000..bd4788b83aa7 --- /dev/null +++ b/applications/system/hid_app/views/hid_numpad.c @@ -0,0 +1,318 @@ +#include "hid_numpad.h" +#include +#include +#include +#include "../hid.h" +#include "hid_icons.h" + +#define TAG "HidNumpad" + +struct HidNumpad { + View* view; + Hid* hid; +}; + +typedef struct { + uint8_t last_x; + uint8_t last_y; + uint8_t x; + uint8_t y; + uint8_t last_key_code; + uint16_t modifier_code; + bool ok_pressed; + bool back_pressed; + bool connected; + char key_string[5]; + HidTransport transport; +} HidNumpadModel; + +typedef struct { + uint8_t width; + char* key; + uint8_t height; + const Icon* icon; + uint8_t value; +} HidNumpadKey; + +typedef struct { + int8_t x; + int8_t y; +} HidNumpadPoint; + +#define MARGIN_TOP 32 +#define MARGIN_LEFT 1 +#define KEY_WIDTH 20 +#define KEY_HEIGHT 15 +#define KEY_PADDING 1 +#define ROW_COUNT 6 +#define COLUMN_COUNT 3 + +const HidNumpadKey hid_numpad_keyset[ROW_COUNT][COLUMN_COUNT] = { + { + {.width = 1, .height = 1, .icon = NULL, .key = "NL", .value = HID_KEYPAD_NUMLOCK}, + {.width = 1, .height = 1, .icon = NULL, .key = "/", .value = HID_KEYPAD_SLASH}, + {.width = 1, .height = 1, .icon = NULL, .key = "*", .value = HID_KEYPAD_ASTERISK}, + // {.width = 1, .height = 1, .icon = NULL, .key = "-", .value = HID_KEYPAD_MINUS}, + }, + { + {.width = 1, .height = 1, .icon = NULL, .key = "7", .value = HID_KEYPAD_7}, + {.width = 1, .height = 1, .icon = NULL, .key = "8", .value = HID_KEYBOARD_8}, + {.width = 1, .height = 1, .icon = NULL, .key = "9", .value = HID_KEYBOARD_9}, + // {.width = 1, .height = 2, .icon = NULL, .key = "+", .value = HID_KEYPAD_PLUS}, + }, + { + {.width = 1, .height = 1, .icon = NULL, .key = "4", .value = HID_KEYPAD_4}, + {.width = 1, .height = 1, .icon = NULL, .key = "5", .value = HID_KEYPAD_5}, + {.width = 1, .height = 1, .icon = NULL, .key = "6", .value = HID_KEYPAD_6}, + }, + { + {.width = 1, .height = 1, .icon = NULL, .key = "1", .value = HID_KEYPAD_1}, + {.width = 1, .height = 1, .icon = NULL, .key = "2", .value = HID_KEYPAD_2}, + {.width = 1, .height = 1, .icon = NULL, .key = "3", .value = HID_KEYPAD_3}, + // {.width = 1, .height = 2, .icon = NULL, .key = "En", .value = HID_KEYPAD_ENTER}, + }, + { + {.width = 2, .height = 1, .icon = NULL, .key = "0", .value = HID_KEYBOARD_0}, + {.width = 0, .height = 0, .icon = NULL, .key = "0", .value = HID_KEYBOARD_0}, + {.width = 1, .height = 1, .icon = NULL, .key = ".", .value = HID_KEYPAD_DOT}, + }, + { + {.width = 1, .height = 1, .icon = NULL, .key = "En", .value = HID_KEYPAD_ENTER}, + {.width = 1, .height = 1, .icon = NULL, .key = "-", .value = HID_KEYPAD_MINUS}, + {.width = 1, .height = 1, .icon = NULL, .key = "+", .value = HID_KEYPAD_PLUS}, + }, +}; + +static void hid_numpad_draw_key( + Canvas* canvas, + HidNumpadModel* model, + uint8_t x, + uint8_t y, + HidNumpadKey key, + bool selected) { + if(!key.width || !key.height) return; + + canvas_set_color(canvas, ColorBlack); + uint8_t keyWidth = KEY_WIDTH * key.width + KEY_PADDING * (key.width - 1); + uint8_t keyHeight = KEY_HEIGHT * key.height + KEY_PADDING * (key.height - 1); + if(selected) { + elements_slightly_rounded_box( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), + keyWidth, + keyHeight); + canvas_set_color(canvas, ColorWhite); + } else { + elements_slightly_rounded_frame( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), + keyWidth, + keyHeight); + } + if(key.icon != NULL) { + canvas_draw_icon( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 - key.icon->width / 2, + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + keyHeight / 2 - key.icon->height / 2, + key.icon); + } else { + strcpy(model->key_string, key.key); + canvas_draw_str_aligned( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 + 1, + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + keyHeight / 2 + 1, + AlignCenter, + AlignCenter, + model->key_string); + } +} + +static void hid_numpad_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidNumpadModel* model = context; + + // Header + canvas_set_font(canvas, FontPrimary); + if(model->transport == HidTransportBle) { + if(model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + elements_multiline_text_aligned( + canvas, 7, 60, AlignLeft, AlignBottom, "Waiting for\nConnection..."); + } + elements_multiline_text_aligned(canvas, 20, 3, AlignLeft, AlignTop, "Numpad"); + + } else { + elements_multiline_text_aligned(canvas, 12, 3, AlignLeft, AlignTop, "Numpad"); + } + + canvas_draw_icon(canvas, 3, 18, &I_Pin_back_arrow_10x8); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned(canvas, 15, 19, AlignLeft, AlignTop, "Hold to exit"); + + if(!model->connected && (model->transport == HidTransportBle)) { + return; + } + + canvas_set_font(canvas, FontKeyboard); + uint8_t initY = 0; // = model->y == 0 ? 0 : 1; + + // if(model->y > ROW_COUNT) { + // initY = model->y - (ROW_COUNT - 1); + // } + + for(uint8_t y = initY; y < ROW_COUNT; y++) { + const HidNumpadKey* numpadKeyRow = hid_numpad_keyset[y]; + uint8_t x = 0; + for(uint8_t i = 0; i < COLUMN_COUNT; i++) { + HidNumpadKey key = numpadKeyRow[i]; + bool keySelected = (x <= model->x && model->x < (x + key.width)) && y == model->y; + bool backSelected = model->back_pressed && key.value == HID_KEYBOARD_DELETE; + hid_numpad_draw_key( + canvas, + model, + x, + y - initY, + key, + (!model->ok_pressed && keySelected) || backSelected); + x += key.width; + } + } +} + +static uint8_t hid_numpad_get_selected_key(HidNumpadModel* model) { + HidNumpadKey key = hid_numpad_keyset[model->y][model->x]; + return key.value; +} + +static void hid_numpad_get_select_key(HidNumpadModel* model, HidNumpadPoint delta) { + do { + const int delta_sum = model->y + delta.y; + model->y = delta_sum < 0 ? ROW_COUNT - 1 : delta_sum % ROW_COUNT; + } while(delta.y != 0 && hid_numpad_keyset[model->y][model->x].value == 0); + + do { + const int delta_sum = model->x + delta.x; + model->x = delta_sum < 0 ? COLUMN_COUNT - 1 : delta_sum % COLUMN_COUNT; + } while(delta.x != 0 && hid_numpad_keyset[model->y][model->x].width == 0); +} + +static void hid_numpad_process(HidNumpad* hid_numpad, InputEvent* event) { + with_view_model( + hid_numpad->view, + HidNumpadModel * model, + { + if(event->key == InputKeyOk) { + if(event->type == InputTypePress) { + model->ok_pressed = true; + } else if(event->type == InputTypeLong || event->type == InputTypeShort) { + model->last_key_code = hid_numpad_get_selected_key(model); + hid_hal_keyboard_press( + hid_numpad->hid, model->modifier_code | model->last_key_code); + } else if(event->type == InputTypeRelease) { + hid_hal_keyboard_release( + hid_numpad->hid, model->modifier_code | model->last_key_code); + model->ok_pressed = false; + } + } else if(event->key == InputKeyBack) { + if(event->type == InputTypePress) { + model->back_pressed = true; + } else if(event->type == InputTypeShort) { + hid_hal_keyboard_press(hid_numpad->hid, HID_KEYBOARD_DELETE); + hid_hal_keyboard_release(hid_numpad->hid, HID_KEYBOARD_DELETE); + } else if(event->type == InputTypeRelease) { + model->back_pressed = false; + } + } else if(event->type == InputTypePress || event->type == InputTypeRepeat) { + if(event->key == InputKeyUp) { + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 0, .y = -1}); + } else if(event->key == InputKeyDown) { + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 0, .y = 1}); + } else if(event->key == InputKeyLeft) { + if(model->last_x == 2 && model->last_y == 2 && model->y == 1 && + model->x == 3) { + model->x = model->last_x; + model->y = model->last_y; + } else if( + model->last_x == 2 && model->last_y == 4 && model->y == 3 && + model->x == 3) { + model->x = model->last_x; + model->y = model->last_y; + } else + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = -1, .y = 0}); + model->last_x = 0; + model->last_y = 0; + } else if(event->key == InputKeyRight) { + if(model->x == 2 && model->y == 2) { + model->last_x = model->x; + model->last_y = model->y; + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 1, .y = -1}); + } else if(model->x == 2 && model->y == 4) { + model->last_x = model->x; + model->last_y = model->y; + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 1, .y = -1}); + } else { + hid_numpad_get_select_key(model, (HidNumpadPoint){.x = 1, .y = 0}); + } + } + } + }, + true); +} + +static bool hid_numpad_input_callback(InputEvent* event, void* context) { + furi_assert(context); + HidNumpad* hid_numpad = context; + bool consumed = false; + + if(event->type == InputTypeLong && event->key == InputKeyBack) { + hid_hal_keyboard_release_all(hid_numpad->hid); + } else { + hid_numpad_process(hid_numpad, event); + consumed = true; + } + + return consumed; +} + +HidNumpad* hid_numpad_alloc(Hid* bt_hid) { + HidNumpad* hid_numpad = malloc(sizeof(HidNumpad)); + hid_numpad->view = view_alloc(); + hid_numpad->hid = bt_hid; + view_set_context(hid_numpad->view, hid_numpad); + view_allocate_model(hid_numpad->view, ViewModelTypeLocking, sizeof(HidNumpadModel)); + view_set_orientation(hid_numpad->view, ViewOrientationVertical); + view_set_draw_callback(hid_numpad->view, hid_numpad_draw_callback); + view_set_input_callback(hid_numpad->view, hid_numpad_input_callback); + + with_view_model( + hid_numpad->view, + HidNumpadModel * model, + { + model->transport = bt_hid->transport; + model->y = 0; + }, + true); + + return hid_numpad; +} + +void hid_numpad_free(HidNumpad* hid_numpad) { + furi_assert(hid_numpad); + view_free(hid_numpad->view); + free(hid_numpad); +} + +View* hid_numpad_get_view(HidNumpad* hid_numpad) { + furi_assert(hid_numpad); + return hid_numpad->view; +} + +void hid_numpad_set_connected_status(HidNumpad* hid_numpad, bool connected) { + furi_assert(hid_numpad); + with_view_model( + hid_numpad->view, HidNumpadModel * model, { model->connected = connected; }, true); +} diff --git a/applications/system/hid_app/views/hid_numpad.h b/applications/system/hid_app/views/hid_numpad.h new file mode 100644 index 000000000000..d9bf54df9edc --- /dev/null +++ b/applications/system/hid_app/views/hid_numpad.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidNumpad HidNumpad; + +HidNumpad* hid_numpad_alloc(Hid* bt_hid); + +void hid_numpad_free(HidNumpad* hid_numpad); + +View* hid_numpad_get_view(HidNumpad* hid_numpad); + +void hid_numpad_set_connected_status(HidNumpad* hid_numpad, bool connected); diff --git a/applications/system/hid_app/views/hid_ptt.c b/applications/system/hid_app/views/hid_ptt.c new file mode 100644 index 000000000000..8b2967166e31 --- /dev/null +++ b/applications/system/hid_app/views/hid_ptt.c @@ -0,0 +1,459 @@ +#include "hid_ptt.h" +#include +#include +#include "../hid.h" +#include "../views.h" + +#include "hid_icons.h" + +#define TAG "HidPtt" + +struct HidPtt { + View* view; + Hid* hid; +}; + +typedef struct { + bool left_pressed; + bool up_pressed; + bool right_pressed; + bool down_pressed; + bool muted; + bool ptt_pressed; + bool mic_pressed; + bool mic_sync_pressed; + bool connected; + bool is_mac_os; + uint32_t appIndex; + HidTransport transport; +} HidPttModel; + +enum HidPttAppIndex { + HidPttAppIndexGoogleMeet, + HidPttAppIndexZoom, + HidPttAppIndexFaceTime, + HidPttAppIndexSkype, + HidPttAppIndexSize, +}; + +static void hid_ptt_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidPttModel* model = context; + + // Header + canvas_set_font(canvas, FontPrimary); + if(model->transport == HidTransportBle) { + if(model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + } + } + + // App selection + const uint8_t y_app = 78; + canvas_set_font(canvas, FontSecondary); + canvas_draw_icon(canvas, 0, y_app, &I_ButtonLeft_4x7); + if(model->appIndex == HidPttAppIndexGoogleMeet) { + elements_multiline_text_aligned(canvas, 7, y_app, AlignLeft, AlignTop, "Google Meet"); + } else if(model->appIndex == HidPttAppIndexZoom) { + elements_multiline_text_aligned(canvas, 7, y_app, AlignLeft, AlignTop, "Zoom"); + } else if(model->appIndex == HidPttAppIndexFaceTime) { + elements_multiline_text_aligned(canvas, 7, y_app, AlignLeft, AlignTop, "FaceTime"); + } else if(model->appIndex == HidPttAppIndexSkype) { + elements_multiline_text_aligned(canvas, 7, y_app, AlignLeft, AlignTop, "Skype"); + } + canvas_draw_icon(canvas, 60, y_app, &I_ButtonRight_4x7); + + // OS selection + const uint8_t y_os = 88; + const uint8_t x_os = 7; + // elements_slightly_rounded_box(canvas, model->is_mac_os ? 0 : 26, y_os, model->is_mac_os ? 21 : 26, 11); + elements_slightly_rounded_box(canvas, model->is_mac_os ? x_os : x_os + 26, y_os, model->is_mac_os ? 21 : 26, 11); + canvas_set_color(canvas, model->is_mac_os ? ColorWhite : ColorBlack); + elements_multiline_text_aligned(canvas, x_os + 2, y_os + 1, AlignLeft, AlignTop, "Mac"); + canvas_set_color(canvas, ColorBlack); + if (model->appIndex != HidPttAppIndexFaceTime) { + elements_multiline_text_aligned(canvas, x_os + 23, y_os + 2, AlignLeft, AlignTop, "|"); + canvas_set_color(canvas, model->is_mac_os ? ColorBlack : ColorWhite); + elements_multiline_text_aligned(canvas, x_os + 28, y_os + 2, AlignLeft, AlignTop, "Linux"); + canvas_set_color(canvas, ColorBlack); + } + + // Mic label + const uint8_t y_mic = 102; + canvas_draw_icon(canvas, 0, y_mic - 1, &I_Pin_back_arrow_rotated_8x10); + canvas_draw_icon(canvas, 18, y_mic - 1, &I_Ok_btn_9x9); + elements_multiline_text_aligned(canvas, 11, y_mic, AlignLeft, AlignTop, "+ to sync"); + elements_multiline_text_aligned(canvas, 20, y_mic+10, AlignLeft, AlignTop, "mic status"); + + // Exit label + canvas_draw_icon(canvas, 20, 121, &I_ButtonLeft_4x7); + elements_multiline_text_aligned(canvas, 0, 121, AlignLeft, AlignTop, "Hold to exit"); + + const uint8_t x_1 = 0; + const uint8_t x_2 = x_1 + 19 + 4; + const uint8_t x_3 = x_1 + 19 * 2 + 8; + + const uint8_t y_1 = 19; + const uint8_t y_2 = y_1 + 19; + const uint8_t y_3 = y_2 + 19; + if(!model->ptt_pressed || model->mic_pressed || model->up_pressed || model->down_pressed || model->left_pressed || model->right_pressed || model->mic_sync_pressed) { + // Up + canvas_draw_icon(canvas, x_2, y_1, &I_Button_18x18); + if(model->up_pressed) { + elements_slightly_rounded_box(canvas, x_2 + 3, y_1 + 2, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + if(model->mic_pressed) { + if (model->appIndex != HidPttAppIndexFaceTime) { + elements_multiline_text_aligned(canvas, x_2 + 4, y_1 + 5, AlignLeft, AlignTop, "OS"); + } + } else { + canvas_draw_icon(canvas, x_2 + 5, y_1 + 5, &I_Volup_8x6); + } + canvas_set_color(canvas, ColorBlack); + + // Down + canvas_draw_icon(canvas, x_2, y_3, &I_Button_18x18); + if(model->down_pressed) { + elements_slightly_rounded_box(canvas, x_2 + 3, y_3 + 2, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + if(!model->mic_pressed) { + canvas_draw_icon(canvas, x_2 + 6, y_3 + 5, &I_Voldwn_6x6); + } + canvas_set_color(canvas, ColorBlack); + + // Left + canvas_draw_icon(canvas, x_1, y_2, &I_Button_18x18); + if(model->left_pressed) { + elements_slightly_rounded_box(canvas, x_1 + 3, y_2 + 2, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + if (model->mic_pressed) { + canvas_draw_icon(canvas, x_1 + 7, y_2 + 5, &I_ButtonLeft_4x7); + } else { + canvas_draw_icon(canvas, x_1 + 4, y_2 + 5, &I_Pin_back_arrow_10x8); + } + canvas_set_color(canvas, ColorBlack); + + // Right / Camera + canvas_draw_icon(canvas, x_3, y_2, &I_Button_18x18); + if(model->right_pressed) { + elements_slightly_rounded_box(canvas, x_3 + 3, y_2 + 2, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + if(!model->mic_pressed) { + if (model->appIndex != HidPttAppIndexFaceTime) { + canvas_draw_icon(canvas, x_3 + 11, y_2 + 5, &I_ButtonLeft_4x7); + canvas_draw_box(canvas, x_3 + 4, y_2 + 5, 7, 7); + } + } else { + canvas_draw_icon(canvas, x_3 + 8, y_2 + 5, &I_ButtonRight_4x7); + } + canvas_set_color(canvas, ColorBlack); + + // Back / Mic + const uint8_t x_mic = x_3; + canvas_draw_icon(canvas, x_mic, 0, &I_Button_18x18); + if(model->mic_pressed) { + elements_slightly_rounded_box(canvas, x_mic + 3, 2, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, x_mic + 5, 4, &I_Mic_btn_8x10); + if(model->muted) { + canvas_draw_line(canvas, x_mic + 3, 2 , x_mic + 3 + 13, 2 + 13); + canvas_draw_line(canvas, x_mic + 2, 2 , x_mic + 2 + 13, 2 + 13); + canvas_draw_line(canvas, x_mic + 3, 2 + 13, x_mic + 3 + 13, 2); + canvas_draw_line(canvas, x_mic + 2, 2 + 13, x_mic + 2 + 13, 2); + } + canvas_set_color(canvas, ColorBlack); + } + + // Ok / PTT + const uint8_t x_ptt_margin = 4; + const uint8_t x_ptt_width = 17; + const uint8_t x_ptt = x_1 + 19; + canvas_draw_icon(canvas, x_ptt , y_2 , &I_BtnFrameLeft_3x18); + canvas_draw_icon(canvas, x_ptt + x_ptt_width + 3 + x_ptt_margin, y_2 , &I_BtnFrameRight_2x18); + canvas_draw_line(canvas, x_ptt + 3 , y_2 , x_ptt + x_ptt_width + 2 + x_ptt_margin, y_2); + canvas_draw_line(canvas, x_ptt + 3 , y_2 + 16, x_ptt + x_ptt_width + 2 + x_ptt_margin, y_2 + 16); + canvas_draw_line(canvas, x_ptt + 3 , y_2 + 17, x_ptt + x_ptt_width + 2 + x_ptt_margin, y_2 + 17); + + if (!model->ptt_pressed && !model->muted && model->mic_pressed) { + elements_slightly_rounded_box(canvas, x_ptt + 3, y_2 + 2, (x_ptt_width + x_ptt_margin) / 2, 13); + canvas_set_color(canvas, ColorWhite); + } + if (model->mic_pressed) { + canvas_draw_icon(canvas, x_ptt + 4, y_2 + 4, &I_Mic_btn_8x10); + } + canvas_set_color(canvas, ColorBlack); + if(!model->ptt_pressed && model->muted && model->mic_pressed) { + elements_slightly_rounded_box(canvas, x_ptt + 3 + (x_ptt_width + x_ptt_margin) / 2, y_2 + 2, (x_ptt_width + x_ptt_margin) / 2, 13); + canvas_set_color(canvas, ColorWhite); + } + if (model->mic_pressed) { + canvas_draw_icon(canvas, x_ptt + 14, y_2 + 4, &I_Mic_btn_8x10); + canvas_draw_line(canvas, x_ptt + 13, y_2 + 3 , x_ptt + 22, y_2 + 14); + canvas_draw_line(canvas, x_ptt + 13, y_2 + 14, x_ptt + 22, y_2 + 3); + } else { + if (model->ptt_pressed && !model->mic_sync_pressed) { + elements_slightly_rounded_box(canvas, x_ptt + 3, y_2 + 2, x_ptt_width + x_ptt_margin, 13); + canvas_set_color(canvas, ColorWhite); + } + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, x_ptt + 2 + x_ptt_margin / 2, y_2 + 13, AlignLeft, AlignBottom, "PTT"); + canvas_set_font(canvas, FontSecondary); + } + canvas_set_color(canvas, ColorBlack); +} + +static void hid_ptt_trigger_mute(HidPtt* hid_ptt, HidPttModel * model) { + if(model->appIndex == HidPttAppIndexGoogleMeet && model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_D); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_D ); + } else if(model->appIndex == HidPttAppIndexGoogleMeet && !model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_D); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_D ); + } else if(model->appIndex == HidPttAppIndexZoom && model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_A); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_A ); + } else if(model->appIndex == HidPttAppIndexFaceTime) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M ); + } else if(model->appIndex == HidPttAppIndexSkype && model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M ); + } else if(model->appIndex == HidPttAppIndexSkype && !model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M ); + } +} + +static void hid_ptt_trigger_camera(HidPtt* hid_ptt, HidPttModel * model) { + if(model->appIndex == HidPttAppIndexGoogleMeet && model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_E); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI | HID_KEYBOARD_E ); + } else if(model->appIndex == HidPttAppIndexGoogleMeet && !model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_E); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_E ); + } else if(model->appIndex == HidPttAppIndexZoom && model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_V ); + } else if(model->appIndex == HidPttAppIndexZoom && !model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_V); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_ALT | HID_KEYBOARD_V ); + } else if(model->appIndex == HidPttAppIndexSkype && model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K ); + } else if(model->appIndex == HidPttAppIndexSkype && !model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_K ); + } +} + +static void hid_ptt_start_ptt(HidPtt* hid_ptt, HidPttModel * model) { + if(model->appIndex == HidPttAppIndexGoogleMeet) { + hid_hal_keyboard_press(hid_ptt->hid, HID_KEYBOARD_SPACEBAR); + } else if(model->appIndex == HidPttAppIndexZoom) { + hid_hal_keyboard_press(hid_ptt->hid, HID_KEYBOARD_SPACEBAR); + } else if(model->appIndex == HidPttAppIndexFaceTime) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M ); + } else if(model->appIndex == HidPttAppIndexSkype && model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M ); + } else if(model->appIndex == HidPttAppIndexSkype && !model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M ); + } +} + +static void hid_ptt_stop_ptt(HidPtt* hid_ptt, HidPttModel * model) { + if(model->appIndex == HidPttAppIndexGoogleMeet) { + hid_hal_keyboard_release(hid_ptt->hid, HID_KEYBOARD_SPACEBAR); + } else if(model->appIndex == HidPttAppIndexZoom) { + hid_hal_keyboard_release(hid_ptt->hid, HID_KEYBOARD_SPACEBAR); + } else if(model->appIndex == HidPttAppIndexFaceTime) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M ); + } else if(model->appIndex == HidPttAppIndexSkype && model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_GUI| KEY_MOD_LEFT_SHIFT | HID_KEYBOARD_M ); + } else if(model->appIndex == HidPttAppIndexSkype && !model->is_mac_os) { + hid_hal_keyboard_press( hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M); + hid_hal_keyboard_release(hid_ptt->hid, KEY_MOD_LEFT_CTRL | HID_KEYBOARD_M ); + } +} + +// Supports only ±1 +static void hid_ptt_shift_app(HidPttModel * model, int shift) { + int i = (short) model->appIndex; + if (i + shift >= HidPttAppIndexSize) { + model->appIndex = 0; + } else if(i + shift <= 0) { + model->appIndex = HidPttAppIndexSize - 1; + } else { + model->appIndex += shift; + } + // Avoid showing facetime if not macos + if (model->appIndex == HidPttAppIndexFaceTime && !model->is_mac_os) { + hid_ptt_shift_app(model, shift); + } +} + +static void hid_ptt_process(HidPtt* hid_ptt, InputEvent* event) { + with_view_model( + hid_ptt->view, + HidPttModel * model, + { + if(event->type == InputTypePress && !model->ptt_pressed) { + if(event->key == InputKeyUp) { + model->up_pressed = true; + if (!model->mic_pressed){ + hid_hal_consumer_key_press(hid_ptt->hid, HID_CONSUMER_VOLUME_INCREMENT); + } else { + if (model->appIndex != HidPttAppIndexFaceTime) { + model->is_mac_os = !model->is_mac_os; + notification_message(hid_ptt->hid->notifications, &sequence_single_vibro); + } + } + } else if(event->key == InputKeyDown) { + model->down_pressed = true; + if (!model->mic_pressed){ + hid_hal_consumer_key_press(hid_ptt->hid, HID_CONSUMER_VOLUME_DECREMENT); + } else if (!model->mic_pressed) { + hid_ptt_shift_app(model, - 1); + notification_message(hid_ptt->hid->notifications, &sequence_single_vibro); + } + } else if(event->key == InputKeyLeft) { + model->left_pressed = true; + if (model->mic_pressed){ + hid_ptt_shift_app(model, 1); + notification_message(hid_ptt->hid->notifications, &sequence_single_vibro); + } + } else if(event->key == InputKeyRight) { + model->right_pressed = true; + if (model->mic_pressed){ + hid_ptt_shift_app(model, - 1); + notification_message(hid_ptt->hid->notifications, &sequence_single_vibro); + } + } else if(event->key == InputKeyOk) { + model->ptt_pressed = true; + if (model->mic_pressed){ + // Change local mic status + model->muted = !model->muted; + model->mic_sync_pressed = true; + notification_message(hid_ptt->hid->notifications, &sequence_single_vibro); + } else { + if (model->muted) { + hid_ptt_start_ptt(hid_ptt, model); + } + } + } else if(event->key == InputKeyBack) { + model->mic_pressed = true; + } + } else if(event->type == InputTypeRelease) { + if(event->key == InputKeyUp) { + model->up_pressed = false; + if (!model->mic_pressed && !model->ptt_pressed){ + hid_hal_consumer_key_release(hid_ptt->hid, HID_CONSUMER_VOLUME_INCREMENT); + } + } else if(event->key == InputKeyDown) { + model->down_pressed = false; + if (!model->mic_pressed && !model->ptt_pressed){ + hid_hal_consumer_key_release(hid_ptt->hid, HID_CONSUMER_VOLUME_DECREMENT); + } + } else if(event->key == InputKeyLeft) { + model->left_pressed = false; + } else if(event->key == InputKeyRight) { + model->right_pressed = false; + + } else if(event->key == InputKeyOk) { + model->ptt_pressed = false; + if(!model->mic_pressed && !model->mic_sync_pressed) { + if (model->muted) { + hid_ptt_stop_ptt(hid_ptt, model); + } else { + hid_ptt_trigger_mute(hid_ptt, model); + model->muted = true; + } + } + model->mic_sync_pressed = false; + } else if(event->key == InputKeyBack) { + model->mic_pressed = false; + } + } else if(event->type == InputTypeShort && !model->ptt_pressed) { + if(event->key == InputKeyBack ) { // no changes if PTT is pressed + model->muted = !model->muted; + hid_ptt_trigger_mute(hid_ptt, model); + } else if(event->key == InputKeyRight) { + if (!model->mic_pressed){ + hid_ptt_trigger_camera(hid_ptt, model); + } + } + } else if(event->type == InputTypeLong && event->key == InputKeyLeft) { + model->left_pressed = false; + if (!model->ptt_pressed){ + hid_hal_keyboard_release_all(hid_ptt->hid); + view_dispatcher_switch_to_view(hid_ptt->hid->view_dispatcher, HidViewSubmenu); + // sequence_double_vibro to notify that we quit PTT + notification_message(hid_ptt->hid->notifications, &sequence_double_vibro); + } + } + //LED + if (model->muted && !model->ptt_pressed) { + notification_message(hid_ptt->hid->notifications, &sequence_reset_red); + } else { + notification_message(hid_ptt->hid->notifications, &sequence_set_red_255); + } + }, + true); +} + +static bool hid_ptt_input_callback(InputEvent* event, void* context) { + furi_assert(context); + HidPtt* hid_ptt = context; + bool consumed = true; + hid_ptt_process(hid_ptt, event); + return consumed; +} + +HidPtt* hid_ptt_alloc(Hid* hid) { + HidPtt* hid_ptt = malloc(sizeof(HidPtt)); + hid_ptt->view = view_alloc(); + hid_ptt->hid = hid; + view_set_context(hid_ptt->view, hid_ptt); + view_allocate_model(hid_ptt->view, ViewModelTypeLocking, sizeof(HidPttModel)); + view_set_draw_callback(hid_ptt->view, hid_ptt_draw_callback); + view_set_input_callback(hid_ptt->view, hid_ptt_input_callback); + view_set_orientation(hid_ptt->view, ViewOrientationVerticalFlip); + + with_view_model( + hid_ptt->view, HidPttModel * model, { + model->transport = hid->transport; + model->muted = true; // assume we're muted + model->is_mac_os = true; + model->mic_sync_pressed = false; + }, true); + return hid_ptt; +} + +void hid_ptt_free(HidPtt* hid_ptt) { + furi_assert(hid_ptt); + notification_message(hid_ptt->hid->notifications, &sequence_reset_red); + view_free(hid_ptt->view); + free(hid_ptt); +} + +View* hid_ptt_get_view(HidPtt* hid_ptt) { + furi_assert(hid_ptt); + return hid_ptt->view; +} + +void hid_ptt_set_connected_status(HidPtt* hid_ptt, bool connected) { + furi_assert(hid_ptt); + with_view_model( + hid_ptt->view, HidPttModel * model, { model->connected = connected; }, true); +} diff --git a/applications/system/hid_app/views/hid_ptt.h b/applications/system/hid_app/views/hid_ptt.h new file mode 100644 index 000000000000..eb205c20e155 --- /dev/null +++ b/applications/system/hid_app/views/hid_ptt.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidPtt HidPtt; + +HidPtt* hid_ptt_alloc(Hid* bt_hid); + +void hid_ptt_free(HidPtt* hid_ptt); + +View* hid_ptt_get_view(HidPtt* hid_ptt); + +void hid_ptt_set_connected_status(HidPtt* hid_ptt, bool connected); diff --git a/applications/system/hid_app/views/hid_tikshorts.c b/applications/system/hid_app/views/hid_tikshorts.c new file mode 100644 index 000000000000..6965c1331833 --- /dev/null +++ b/applications/system/hid_app/views/hid_tikshorts.c @@ -0,0 +1,271 @@ +#include "hid_tikshorts.h" +#include "../hid.h" +#include + +#include "hid_icons.h" + +#define TAG "HidTikShorts" + +struct HidTikShorts { + View* view; + Hid* hid; +}; + +typedef struct { + bool left_pressed; + bool up_pressed; + bool right_pressed; + bool down_pressed; + bool ok_pressed; + bool connected; + bool is_cursor_set; + bool back_mouse_pressed; + HidTransport transport; +} HidTikShortsModel; + +static void hid_tikshorts_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidTikShortsModel* model = context; + + // Header + if(model->transport == HidTransportBle) { + if(model->connected) { + canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); + } else { + canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); + } + } + + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "TikTok /"); + elements_multiline_text_aligned(canvas, 3, 18, AlignLeft, AlignTop, "YT Shorts"); + canvas_set_font(canvas, FontSecondary); + + // Keypad circles + canvas_draw_icon(canvas, 58, 3, &I_OutCircles_70x51); + + // Pause + if(model->back_mouse_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 107, 33, &I_Pressed_Button_19x19); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 113, 37, &I_Pause_icon_9x9); + canvas_set_color(canvas, ColorBlack); + + // Up + if(model->up_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 68, 6, &I_S_UP_31x15); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 80, 8, &I_Arr_up_7x9); + canvas_set_color(canvas, ColorBlack); + + // Down + if(model->down_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 68, 36, &I_S_DOWN_31x15); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 80, 40, &I_Arr_dwn_7x9); + canvas_set_color(canvas, ColorBlack); + + // Left + if(model->left_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 61, 13, &I_S_LEFT_15x31); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 64, 25, &I_Voldwn_6x6); + canvas_set_color(canvas, ColorBlack); + + // Right + if(model->right_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 91, 13, &I_S_RIGHT_15x31); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 95, 25, &I_Volup_8x6); + canvas_set_color(canvas, ColorBlack); + + // Ok + if(model->ok_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 74, 19, &I_Pressed_Button_19x19); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 78, 25, &I_Like_def_11x9); + canvas_set_color(canvas, ColorBlack); + + // Exit + canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); +} + +static void hid_tikshorts_reset_cursor(HidTikShorts* hid_tikshorts) { + // Set cursor to the phone's left up corner + // Delays to guarantee one packet per connection interval + for(size_t i = 0; i < 8; i++) { + hid_hal_mouse_move(hid_tikshorts->hid, -127, -127); + furi_delay_ms(50); + } + // Move cursor from the corner + hid_hal_mouse_move(hid_tikshorts->hid, 20, 120); + furi_delay_ms(50); +} + +static void hid_tikshorts_process_press( + HidTikShorts* hid_tikshorts, + HidTikShortsModel* model, + InputEvent* event) { + if(event->key == InputKeyUp) { + model->up_pressed = true; + } else if(event->key == InputKeyDown) { + model->down_pressed = true; + } else if(event->key == InputKeyLeft) { + model->left_pressed = true; + hid_hal_consumer_key_press(hid_tikshorts->hid, HID_CONSUMER_VOLUME_DECREMENT); + } else if(event->key == InputKeyRight) { + model->right_pressed = true; + hid_hal_consumer_key_press(hid_tikshorts->hid, HID_CONSUMER_VOLUME_INCREMENT); + } else if(event->key == InputKeyOk) { + model->ok_pressed = true; + } else if(event->key == InputKeyBack) { + model->back_mouse_pressed = true; + } +} + +static void hid_tikshorts_process_release( + HidTikShorts* hid_tikshorts, + HidTikShortsModel* model, + InputEvent* event) { + if(event->key == InputKeyUp) { + model->up_pressed = false; + } else if(event->key == InputKeyDown) { + model->down_pressed = false; + } else if(event->key == InputKeyLeft) { + model->left_pressed = false; + hid_hal_consumer_key_release(hid_tikshorts->hid, HID_CONSUMER_VOLUME_DECREMENT); + } else if(event->key == InputKeyRight) { + model->right_pressed = false; + hid_hal_consumer_key_release(hid_tikshorts->hid, HID_CONSUMER_VOLUME_INCREMENT); + } else if(event->key == InputKeyOk) { + model->ok_pressed = false; + } else if(event->key == InputKeyBack) { + model->back_mouse_pressed = false; + } +} + +static bool hid_tikshorts_input_callback(InputEvent* event, void* context) { + furi_assert(context); + HidTikShorts* hid_tikshorts = context; + bool consumed = false; + + with_view_model( + hid_tikshorts->view, + HidTikShortsModel * model, + { + if(event->type == InputTypePress) { + hid_tikshorts_process_press(hid_tikshorts, model, event); + if(model->connected && !model->is_cursor_set) { + hid_tikshorts_reset_cursor(hid_tikshorts); + model->is_cursor_set = true; + } + consumed = true; + } else if(event->type == InputTypeRelease) { + hid_tikshorts_process_release(hid_tikshorts, model, event); + consumed = true; + } else if(event->type == InputTypeShort) { + if(event->key == InputKeyOk) { + hid_hal_mouse_press(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT); + furi_delay_ms(25); + hid_hal_mouse_release(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT); + furi_delay_ms(100); + hid_hal_mouse_press(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT); + furi_delay_ms(25); + hid_hal_mouse_release(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT); + consumed = true; + } else if(event->key == InputKeyDown) { + // Swipe to next video + hid_hal_mouse_scroll(hid_tikshorts->hid, 6); + hid_hal_mouse_scroll(hid_tikshorts->hid, 8); + hid_hal_mouse_scroll(hid_tikshorts->hid, 10); + hid_hal_mouse_scroll(hid_tikshorts->hid, 8); + hid_hal_mouse_scroll(hid_tikshorts->hid, 6); + consumed = true; + } else if(event->key == InputKeyUp) { + // Swipe to previous video + hid_hal_mouse_scroll(hid_tikshorts->hid, -6); + hid_hal_mouse_scroll(hid_tikshorts->hid, -8); + hid_hal_mouse_scroll(hid_tikshorts->hid, -10); + hid_hal_mouse_scroll(hid_tikshorts->hid, -8); + hid_hal_mouse_scroll(hid_tikshorts->hid, -6); + consumed = true; + } else if(event->key == InputKeyBack) { + // Pause + hid_hal_mouse_press(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT); + furi_delay_ms(50); + hid_hal_mouse_release(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT); + consumed = true; + } + } else if(event->type == InputTypeLong) { + if(event->key == InputKeyBack) { + hid_hal_consumer_key_release_all(hid_tikshorts->hid); + model->is_cursor_set = false; + consumed = false; + } + } + }, + true); + + return consumed; +} + +HidTikShorts* hid_tikshorts_alloc(Hid* bt_hid) { + HidTikShorts* hid_tikshorts = malloc(sizeof(HidTikShorts)); + hid_tikshorts->hid = bt_hid; + hid_tikshorts->view = view_alloc(); + view_set_context(hid_tikshorts->view, hid_tikshorts); + view_allocate_model(hid_tikshorts->view, ViewModelTypeLocking, sizeof(HidTikShortsModel)); + view_set_draw_callback(hid_tikshorts->view, hid_tikshorts_draw_callback); + view_set_input_callback(hid_tikshorts->view, hid_tikshorts_input_callback); + + with_view_model( + hid_tikshorts->view, + HidTikShortsModel * model, + { model->transport = bt_hid->transport; }, + true); + + return hid_tikshorts; +} + +void hid_tikshorts_free(HidTikShorts* hid_tikshorts) { + furi_assert(hid_tikshorts); + view_free(hid_tikshorts->view); + free(hid_tikshorts); +} + +View* hid_tikshorts_get_view(HidTikShorts* hid_tikshorts) { + furi_assert(hid_tikshorts); + return hid_tikshorts->view; +} + +void hid_tikshorts_set_connected_status(HidTikShorts* hid_tikshorts, bool connected) { + furi_assert(hid_tikshorts); + with_view_model( + hid_tikshorts->view, + HidTikShortsModel * model, + { + model->connected = connected; + model->is_cursor_set = false; + }, + true); +} diff --git a/applications/system/hid_app/views/hid_tikshorts.h b/applications/system/hid_app/views/hid_tikshorts.h new file mode 100644 index 000000000000..5604962ee8e3 --- /dev/null +++ b/applications/system/hid_app/views/hid_tikshorts.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidTikShorts HidTikShorts; + +HidTikShorts* hid_tikshorts_alloc(Hid* bt_hid); + +void hid_tikshorts_free(HidTikShorts* hid_tikshorts); + +View* hid_tikshorts_get_view(HidTikShorts* hid_tikshorts); + +void hid_tikshorts_set_connected_status(HidTikShorts* hid_tikshorts, bool connected); diff --git a/applications/system/hid_app/views/hid_tiktok.c b/applications/system/hid_app/views/hid_tiktok.c deleted file mode 100644 index e1f9f4bed4cb..000000000000 --- a/applications/system/hid_app/views/hid_tiktok.c +++ /dev/null @@ -1,241 +0,0 @@ -#include "hid_tiktok.h" -#include "../hid.h" -#include - -#include "hid_icons.h" - -#define TAG "HidTikTok" - -struct HidTikTok { - View* view; - Hid* hid; -}; - -typedef struct { - bool left_pressed; - bool up_pressed; - bool right_pressed; - bool down_pressed; - bool ok_pressed; - bool connected; - bool is_cursor_set; - HidTransport transport; -} HidTikTokModel; - -static void hid_tiktok_draw_callback(Canvas* canvas, void* context) { - furi_assert(context); - HidTikTokModel* model = context; - - // Header - if(model->transport == HidTransportBle) { - if(model->connected) { - canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15); - } else { - canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15); - } - } - - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "TikTok"); - canvas_set_font(canvas, FontSecondary); - - // Keypad circles - canvas_draw_icon(canvas, 76, 8, &I_Circles_47x47); - - // Up - if(model->up_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 93, 9, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 96, 11, &I_Arr_up_7x9); - canvas_set_color(canvas, ColorBlack); - - // Down - if(model->down_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 93, 41, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 96, 44, &I_Arr_dwn_7x9); - canvas_set_color(canvas, ColorBlack); - - // Left - if(model->left_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 77, 25, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 81, 29, &I_Voldwn_6x6); - canvas_set_color(canvas, ColorBlack); - - // Right - if(model->right_pressed) { - canvas_set_bitmap_mode(canvas, 1); - canvas_draw_icon(canvas, 109, 25, &I_Pressed_Button_13x13); - canvas_set_bitmap_mode(canvas, 0); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 111, 29, &I_Volup_8x6); - canvas_set_color(canvas, ColorBlack); - - // Ok - if(model->ok_pressed) { - canvas_draw_icon(canvas, 91, 23, &I_Like_pressed_17x17); - } else { - canvas_draw_icon(canvas, 94, 27, &I_Like_def_11x9); - } - // Exit - canvas_draw_icon(canvas, 0, 54, &I_Pin_back_arrow_10x8); - canvas_set_font(canvas, FontSecondary); - elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit"); -} - -static void hid_tiktok_reset_cursor(HidTikTok* hid_tiktok) { - // Set cursor to the phone's left up corner - // Delays to guarantee one packet per connection interval - for(size_t i = 0; i < 8; i++) { - hid_hal_mouse_move(hid_tiktok->hid, -127, -127); - furi_delay_ms(50); - } - // Move cursor from the corner - hid_hal_mouse_move(hid_tiktok->hid, 20, 120); - furi_delay_ms(50); -} - -static void - hid_tiktok_process_press(HidTikTok* hid_tiktok, HidTikTokModel* model, InputEvent* event) { - if(event->key == InputKeyUp) { - model->up_pressed = true; - } else if(event->key == InputKeyDown) { - model->down_pressed = true; - } else if(event->key == InputKeyLeft) { - model->left_pressed = true; - hid_hal_consumer_key_press(hid_tiktok->hid, HID_CONSUMER_VOLUME_DECREMENT); - } else if(event->key == InputKeyRight) { - model->right_pressed = true; - hid_hal_consumer_key_press(hid_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT); - } else if(event->key == InputKeyOk) { - model->ok_pressed = true; - } -} - -static void - hid_tiktok_process_release(HidTikTok* hid_tiktok, HidTikTokModel* model, InputEvent* event) { - if(event->key == InputKeyUp) { - model->up_pressed = false; - } else if(event->key == InputKeyDown) { - model->down_pressed = false; - } else if(event->key == InputKeyLeft) { - model->left_pressed = false; - hid_hal_consumer_key_release(hid_tiktok->hid, HID_CONSUMER_VOLUME_DECREMENT); - } else if(event->key == InputKeyRight) { - model->right_pressed = false; - hid_hal_consumer_key_release(hid_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT); - } else if(event->key == InputKeyOk) { - model->ok_pressed = false; - } -} - -static bool hid_tiktok_input_callback(InputEvent* event, void* context) { - furi_assert(context); - HidTikTok* hid_tiktok = context; - bool consumed = false; - - with_view_model( - hid_tiktok->view, - HidTikTokModel * model, - { - if(event->type == InputTypePress) { - hid_tiktok_process_press(hid_tiktok, model, event); - if(model->connected && !model->is_cursor_set) { - hid_tiktok_reset_cursor(hid_tiktok); - model->is_cursor_set = true; - } - consumed = true; - } else if(event->type == InputTypeRelease) { - hid_tiktok_process_release(hid_tiktok, model, event); - consumed = true; - } else if(event->type == InputTypeShort) { - if(event->key == InputKeyOk) { - hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); - hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); - hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - furi_delay_ms(50); - hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT); - consumed = true; - } else if(event->key == InputKeyUp) { - // Emulate up swipe - hid_hal_mouse_scroll(hid_tiktok->hid, -6); - hid_hal_mouse_scroll(hid_tiktok->hid, -12); - hid_hal_mouse_scroll(hid_tiktok->hid, -19); - hid_hal_mouse_scroll(hid_tiktok->hid, -12); - hid_hal_mouse_scroll(hid_tiktok->hid, -6); - consumed = true; - } else if(event->key == InputKeyDown) { - // Emulate down swipe - hid_hal_mouse_scroll(hid_tiktok->hid, 6); - hid_hal_mouse_scroll(hid_tiktok->hid, 12); - hid_hal_mouse_scroll(hid_tiktok->hid, 19); - hid_hal_mouse_scroll(hid_tiktok->hid, 12); - hid_hal_mouse_scroll(hid_tiktok->hid, 6); - consumed = true; - } else if(event->key == InputKeyBack) { - hid_hal_consumer_key_release_all(hid_tiktok->hid); - consumed = true; - } - } else if(event->type == InputTypeLong) { - if(event->key == InputKeyBack) { - hid_hal_consumer_key_release_all(hid_tiktok->hid); - model->is_cursor_set = false; - consumed = false; - } - } - }, - true); - - return consumed; -} - -HidTikTok* hid_tiktok_alloc(Hid* bt_hid) { - HidTikTok* hid_tiktok = malloc(sizeof(HidTikTok)); - hid_tiktok->hid = bt_hid; - hid_tiktok->view = view_alloc(); - view_set_context(hid_tiktok->view, hid_tiktok); - view_allocate_model(hid_tiktok->view, ViewModelTypeLocking, sizeof(HidTikTokModel)); - view_set_draw_callback(hid_tiktok->view, hid_tiktok_draw_callback); - view_set_input_callback(hid_tiktok->view, hid_tiktok_input_callback); - - with_view_model( - hid_tiktok->view, HidTikTokModel * model, { model->transport = bt_hid->transport; }, true); - - return hid_tiktok; -} - -void hid_tiktok_free(HidTikTok* hid_tiktok) { - furi_assert(hid_tiktok); - view_free(hid_tiktok->view); - free(hid_tiktok); -} - -View* hid_tiktok_get_view(HidTikTok* hid_tiktok) { - furi_assert(hid_tiktok); - return hid_tiktok->view; -} - -void hid_tiktok_set_connected_status(HidTikTok* hid_tiktok, bool connected) { - furi_assert(hid_tiktok); - with_view_model( - hid_tiktok->view, - HidTikTokModel * model, - { - model->connected = connected; - model->is_cursor_set = false; - }, - true); -} diff --git a/applications/system/hid_app/views/hid_tiktok.h b/applications/system/hid_app/views/hid_tiktok.h deleted file mode 100644 index b2efc3692d3d..000000000000 --- a/applications/system/hid_app/views/hid_tiktok.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -typedef struct Hid Hid; -typedef struct HidTikTok HidTikTok; - -HidTikTok* hid_tiktok_alloc(Hid* bt_hid); - -void hid_tiktok_free(HidTikTok* hid_tiktok); - -View* hid_tiktok_get_view(HidTikTok* hid_tiktok); - -void hid_tiktok_set_connected_status(HidTikTok* hid_tiktok, bool connected);