diff --git a/applications/system/hid_app/assets/DolphinNice_96x59.png b/applications/system/hid_app/assets/DolphinNice_96x59.png new file mode 100644 index 000000000..a299d3630 Binary files /dev/null and b/applications/system/hid_app/assets/DolphinNice_96x59.png differ diff --git a/applications/system/hid_app/hid.c b/applications/system/hid_app/hid.c index c6d88124c..b712027e2 100644 --- a/applications/system/hid_app/hid.c +++ b/applications/system/hid_app/hid.c @@ -4,6 +4,7 @@ #include "views.h" #include #include +#include "hid_icons.h" #define TAG "HidApp" @@ -19,7 +20,22 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexRemovePairing, }; -static void bt_hid_remove_pairing(Bt* bt) { +bool hid_custom_event_callback(void* context, uint32_t event) { + furi_assert(context); + Hid* app = context; + return scene_manager_handle_custom_event(app->scene_manager, event); +} + +bool hid_back_event_callback(void* context) { + furi_assert(context); + Hid* app = context; + FURI_LOG_D("HID", "Back event"); + scene_manager_next_scene(app->scene_manager, HidSceneExitConfirm); + return true; +} + +void bt_hid_remove_pairing(Hid* app) { + Bt* bt = app->bt; bt_disconnect(bt); // Wait 2nd core to update nvm storage @@ -62,7 +78,7 @@ static void hid_submenu_callback(void* context, uint32_t index) { app->view_id = HidViewMouseJiggler; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler); } else if(index == HidSubmenuIndexRemovePairing) { - bt_hid_remove_pairing(app->bt); + scene_manager_next_scene(app->scene_manager, HidSceneUnpair); } } @@ -86,23 +102,6 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con hid_tiktok_set_connected_status(hid->hid_tiktok, connected); } -static void hid_dialog_callback(DialogExResult result, void* context) { - furi_assert(context); - Hid* app = context; - if(result == DialogExResultLeft) { - view_dispatcher_stop(app->view_dispatcher); - } else if(result == DialogExResultRight) { - view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); // Show last view - } else if(result == DialogExResultCenter) { - view_dispatcher_switch_to_view(app->view_dispatcher, HidViewSubmenu); - } -} - -static uint32_t hid_exit_confirm_view(void* context) { - UNUSED(context); - return HidViewExitConfirm; -} - static uint32_t hid_exit(void* context) { UNUSED(context); return VIEW_NONE; @@ -124,6 +123,12 @@ Hid* hid_alloc() { app->view_dispatcher = view_dispatcher_alloc(); view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_set_navigation_event_callback(app->view_dispatcher, hid_back_event_callback); + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); + + // Scene Manager + app->scene_manager = scene_manager_alloc(&hid_scene_handlers, app); + // Device Type Submenu view app->device_type_submenu = submenu_alloc(); submenu_add_item( @@ -172,58 +177,48 @@ Hid* hid_alloc() { view_dispatcher_add_view( app->view_dispatcher, HidViewSubmenu, submenu_get_view(app->device_type_submenu)); app->view_id = HidViewSubmenu; - view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); return app; } Hid* hid_app_alloc_view(void* context) { furi_assert(context); Hid* app = context; + // Dialog view app->dialog = dialog_ex_alloc(); - dialog_ex_set_result_callback(app->dialog, hid_dialog_callback); - dialog_ex_set_context(app->dialog, app); - dialog_ex_set_left_button_text(app->dialog, "Exit"); - dialog_ex_set_right_button_text(app->dialog, "Stay"); - dialog_ex_set_center_button_text(app->dialog, "Menu"); - dialog_ex_set_header(app->dialog, "Close Current App?", 16, 12, AlignLeft, AlignTop); - view_dispatcher_add_view( - app->view_dispatcher, HidViewExitConfirm, dialog_ex_get_view(app->dialog)); + view_dispatcher_add_view(app->view_dispatcher, HidViewDialog, dialog_ex_get_view(app->dialog)); + + // Popup view + app->popup = popup_alloc(); + view_dispatcher_add_view(app->view_dispatcher, HidViewPopup, popup_get_view(app->popup)); // 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_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_dispatcher_add_view( app->view_dispatcher, HidViewKeyboard, hid_keyboard_get_view(app->hid_keyboard)); // 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_dispatcher_add_view( app->view_dispatcher, HidViewMedia, hid_media_get_view(app->hid_media)); // TikTok view app->hid_tiktok = hid_tiktok_alloc(app); - view_set_previous_callback(hid_tiktok_get_view(app->hid_tiktok), hid_exit_confirm_view); view_dispatcher_add_view( app->view_dispatcher, BtHidViewTikTok, hid_tiktok_get_view(app->hid_tiktok)); // Mouse view app->hid_mouse = hid_mouse_alloc(app); - view_set_previous_callback(hid_mouse_get_view(app->hid_mouse), hid_exit_confirm_view); view_dispatcher_add_view( app->view_dispatcher, HidViewMouse, hid_mouse_get_view(app->hid_mouse)); // 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); view_dispatcher_add_view( app->view_dispatcher, HidViewMouseClicker, @@ -231,8 +226,6 @@ 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); view_dispatcher_add_view( app->view_dispatcher, HidViewMouseJiggler, @@ -251,8 +244,10 @@ void hid_free(Hid* app) { // Free views view_dispatcher_remove_view(app->view_dispatcher, HidViewSubmenu); submenu_free(app->device_type_submenu); - view_dispatcher_remove_view(app->view_dispatcher, HidViewExitConfirm); + view_dispatcher_remove_view(app->view_dispatcher, HidViewDialog); dialog_ex_free(app->dialog); + view_dispatcher_remove_view(app->view_dispatcher, HidViewPopup); + popup_free(app->popup); view_dispatcher_remove_view(app->view_dispatcher, HidViewKeynote); hid_keynote_free(app->hid_keynote); view_dispatcher_remove_view(app->view_dispatcher, HidViewKeyboard); @@ -267,6 +262,7 @@ void hid_free(Hid* app) { hid_mouse_jiggler_free(app->hid_mouse_jiggler); view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok); hid_tiktok_free(app->hid_tiktok); + scene_manager_free(app->scene_manager); view_dispatcher_free(app->view_dispatcher); // Close records @@ -285,6 +281,8 @@ int32_t hid_usb_app(void* p) { UNUSED(p); Hid* app = hid_alloc(); app = hid_app_alloc_view(app); + FURI_LOG_D("HID", "Starting as USB app"); + FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); furi_hal_usb_unlock(); furi_check(furi_hal_usb_set_config(&usb_hid, NULL) == true); @@ -293,6 +291,8 @@ int32_t hid_usb_app(void* p) { dolphin_deed(DolphinDeedPluginStart); + scene_manager_next_scene(app->scene_manager, HidSceneMain); + view_dispatcher_run(app->view_dispatcher); furi_hal_usb_set_config(usb_mode_prev, NULL); @@ -307,6 +307,8 @@ int32_t hid_ble_app(void* p) { Hid* app = hid_alloc(); app = hid_app_alloc_view(app); + FURI_LOG_D("HID", "Starting as BLE app"); + bt_disconnect(app->bt); // Wait 2nd core to update nvm storage @@ -333,6 +335,8 @@ int32_t hid_ble_app(void* p) { dolphin_deed(DolphinDeedPluginStart); + scene_manager_next_scene(app->scene_manager, HidSceneMain); + view_dispatcher_run(app->view_dispatcher); bt_set_status_changed_callback(app->bt, NULL, NULL); diff --git a/applications/system/hid_app/hid.h b/applications/system/hid_app/hid.h index e6e974f30..a79b2bcd3 100644 --- a/applications/system/hid_app/hid.h +++ b/applications/system/hid_app/hid.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,8 @@ #include "views/hid_mouse_jiggler.h" #include "views/hid_tiktok.h" +#include "scenes/hid_scene.h" + #define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys" typedef enum { @@ -40,8 +43,10 @@ struct Hid { Gui* gui; NotificationApp* notifications; ViewDispatcher* view_dispatcher; + SceneManager* scene_manager; Submenu* device_type_submenu; DialogEx* dialog; + Popup* popup; HidKeynote* hid_keynote; HidKeyboard* hid_keyboard; HidMedia* hid_media; @@ -53,6 +58,7 @@ struct Hid { HidTransport transport; uint32_t view_id; }; +void bt_hid_remove_pairing(Hid* app); void hid_hal_keyboard_press(Hid* instance, uint16_t event); void hid_hal_keyboard_release(Hid* instance, uint16_t event); diff --git a/applications/system/hid_app/scenes/hid_scene.c b/applications/system/hid_app/scenes/hid_scene.c new file mode 100644 index 000000000..89399a809 --- /dev/null +++ b/applications/system/hid_app/scenes/hid_scene.c @@ -0,0 +1,30 @@ +#include "hid_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const hid_on_enter_handlers[])(void*) = { +#include "hid_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const hid_on_event_handlers[])(void* context, SceneManagerEvent event) = { +#include "hid_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const hid_on_exit_handlers[])(void* context) = { +#include "hid_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers hid_scene_handlers = { + .on_enter_handlers = hid_on_enter_handlers, + .on_event_handlers = hid_on_event_handlers, + .on_exit_handlers = hid_on_exit_handlers, + .scene_num = HidSceneNum, +}; diff --git a/applications/system/hid_app/scenes/hid_scene.h b/applications/system/hid_app/scenes/hid_scene.h new file mode 100644 index 000000000..9a2e6bb32 --- /dev/null +++ b/applications/system/hid_app/scenes/hid_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) HidScene##id, +typedef enum { +#include "hid_scene_config.h" + HidSceneNum, +} HidScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers hid_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "hid_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); +#include "hid_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); +#include "hid_scene_config.h" +#undef ADD_SCENE diff --git a/applications/system/hid_app/scenes/hid_scene_config.h b/applications/system/hid_app/scenes/hid_scene_config.h new file mode 100644 index 000000000..8f3a788d1 --- /dev/null +++ b/applications/system/hid_app/scenes/hid_scene_config.h @@ -0,0 +1,3 @@ +ADD_SCENE(hid, main, Main) +ADD_SCENE(hid, unpair, Unpair) +ADD_SCENE(hid, exit_confirm, ExitConfirm) \ No newline at end of file diff --git a/applications/system/hid_app/scenes/hid_scene_exit_confirm.c b/applications/system/hid_app/scenes/hid_scene_exit_confirm.c new file mode 100644 index 000000000..94e783e93 --- /dev/null +++ b/applications/system/hid_app/scenes/hid_scene_exit_confirm.c @@ -0,0 +1,45 @@ +#include "../hid.h" +#include "../views.h" + +static void hid_scene_exit_confirm_dialog_callback(DialogExResult result, void* context) { + furi_assert(context); + Hid* app = context; + if(result == DialogExResultLeft) { + view_dispatcher_stop(app->view_dispatcher); + } else if(result == DialogExResultRight) { + scene_manager_previous_scene(app->scene_manager); + } else if(result == DialogExResultCenter) { + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, HidSceneMain); + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewSubmenu); + } +} + +void hid_scene_exit_confirm_on_enter(void* context) { + Hid* app = context; + + // Exit dialog view + dialog_ex_reset(app->dialog); + dialog_ex_set_result_callback(app->dialog, hid_scene_exit_confirm_dialog_callback); + dialog_ex_set_context(app->dialog, app); + dialog_ex_set_left_button_text(app->dialog, "Exit"); + dialog_ex_set_right_button_text(app->dialog, "Stay"); + dialog_ex_set_center_button_text(app->dialog, "Menu"); + dialog_ex_set_header(app->dialog, "Close Current App?", 16, 12, AlignLeft, AlignTop); + + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewDialog); +} + +bool hid_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) { + Hid* app = context; + bool consumed = false; + UNUSED(app); + UNUSED(event); + + return consumed; +} + +void hid_scene_exit_confirm_on_exit(void* context) { + Hid* app = context; + + dialog_ex_reset(app->dialog); +} diff --git a/applications/system/hid_app/scenes/hid_scene_main.c b/applications/system/hid_app/scenes/hid_scene_main.c new file mode 100644 index 000000000..6c4a11682 --- /dev/null +++ b/applications/system/hid_app/scenes/hid_scene_main.c @@ -0,0 +1,22 @@ +#include "../hid.h" +#include "../views.h" + +void hid_scene_main_on_enter(void* context) { + Hid* app = context; + + view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); +} + +bool hid_scene_main_on_event(void* context, SceneManagerEvent event) { + Hid* app = context; + bool consumed = false; + UNUSED(app); + UNUSED(event); + + return consumed; +} + +void hid_scene_main_on_exit(void* context) { + Hid* app = context; + UNUSED(app); +} diff --git a/applications/system/hid_app/scenes/hid_scene_unpair.c b/applications/system/hid_app/scenes/hid_scene_unpair.c new file mode 100644 index 000000000..7b0bbd9e6 --- /dev/null +++ b/applications/system/hid_app/scenes/hid_scene_unpair.c @@ -0,0 +1,63 @@ +#include "../hid.h" +#include "../views.h" +#include "hid_icons.h" + +static void hid_scene_unpair_dialog_callback(DialogExResult result, void* context) { + Hid* app = context; + + if(result == DialogExResultRight) { + // Unpair all devices + bt_hid_remove_pairing(app); + + // Show popup + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewPopup); + } else if(result == DialogExResultLeft) { + scene_manager_previous_scene(app->scene_manager); + } +} + +void hid_scene_unpair_popup_callback(void* context) { + Hid* app = context; + + scene_manager_previous_scene(app->scene_manager); +} + +void hid_scene_unpair_on_enter(void* context) { + Hid* app = context; + + // Un-pair dialog view + dialog_ex_reset(app->dialog); + dialog_ex_set_result_callback(app->dialog, hid_scene_unpair_dialog_callback); + dialog_ex_set_context(app->dialog, app); + dialog_ex_set_header(app->dialog, "Unpair All Devices?", 64, 3, AlignCenter, AlignTop); + dialog_ex_set_text( + app->dialog, "All previous pairings\nwill be lost!", 64, 22, AlignCenter, AlignTop); + dialog_ex_set_left_button_text(app->dialog, "Back"); + dialog_ex_set_right_button_text(app->dialog, "Unpair"); + + // Un-pair success popup view + popup_set_icon(app->popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(app->popup, "Done", 14, 15, AlignLeft, AlignTop); + popup_set_timeout(app->popup, 1500); + popup_set_context(app->popup, app); + popup_set_callback(app->popup, hid_scene_unpair_popup_callback); + popup_enable_timeout(app->popup); + + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewDialog); +} + +bool hid_scene_unpair_on_event(void* context, SceneManagerEvent event) { + Hid* app = context; + bool consumed = false; + UNUSED(app); + UNUSED(event); + + return consumed; +} + +void hid_scene_unpair_on_exit(void* context) { + Hid* app = context; + + dialog_ex_reset(app->dialog); + popup_reset(app->popup); +} diff --git a/applications/system/hid_app/views.h b/applications/system/hid_app/views.h index 1bea3355e..f94a55cc6 100644 --- a/applications/system/hid_app/views.h +++ b/applications/system/hid_app/views.h @@ -7,5 +7,6 @@ typedef enum { HidViewMouseClicker, HidViewMouseJiggler, BtHidViewTikTok, - HidViewExitConfirm, + HidViewDialog, + HidViewPopup, } HidView; \ No newline at end of file