diff --git a/applications/external/hid_app/hid.c b/applications/external/hid_app/hid.c index b679c395cc..f29a3b22af 100644 --- a/applications/external/hid_app/hid.c +++ b/applications/external/hid_app/hid.c @@ -7,6 +7,7 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexKeynote, + HidSubmenuIndexKeynoteVertical, HidSubmenuIndexKeyboard, HidSubmenuIndexMedia, HidSubmenuIndexTikTok, @@ -21,6 +22,9 @@ static void hid_submenu_callback(void* context, uint32_t index) { if(index == HidSubmenuIndexKeynote) { app->view_id = HidViewKeynote; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeynote); + } else if(index == HidSubmenuIndexKeynoteVertical) { + app->view_id = HidViewKeynoteVertical; + view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeynoteVertical); } else if(index == HidSubmenuIndexKeyboard) { app->view_id = HidViewKeyboard; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewKeyboard); @@ -54,6 +58,7 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con } } hid_keynote_set_connected_status(hid->hid_keynote, connected); + hid_keynote_vertical_set_connected_status(hid->hid_keynote_vertical, connected); hid_keyboard_set_connected_status(hid->hid_keyboard, connected); hid_media_set_connected_status(hid->hid_media, connected); hid_mouse_set_connected_status(hid->hid_mouse, connected); @@ -105,6 +110,12 @@ Hid* hid_alloc(HidTransport transport) { app->device_type_submenu = submenu_alloc(); submenu_add_item( app->device_type_submenu, "Keynote", HidSubmenuIndexKeynote, hid_submenu_callback, app); + submenu_add_item( + app->device_type_submenu, + "Keynote Vertical", + HidSubmenuIndexKeynoteVertical, + hid_submenu_callback, + app); submenu_add_item( app->device_type_submenu, "Keyboard", HidSubmenuIndexKeyboard, hid_submenu_callback, app); submenu_add_item( @@ -159,6 +170,15 @@ Hid* hid_app_alloc_view(void* context) { view_dispatcher_add_view( app->view_dispatcher, HidViewKeynote, hid_keynote_get_view(app->hid_keynote)); + // Keynote Vertical view + app->hid_keynote_vertical = hid_keynote_vertical_alloc(app); + view_set_previous_callback( + hid_keynote_vertical_get_view(app->hid_keynote_vertical), hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, + HidViewKeynoteVertical, + hid_keynote_vertical_get_view(app->hid_keynote_vertical)); + // Keyboard view app->hid_keyboard = hid_keyboard_alloc(app); view_set_previous_callback(hid_keyboard_get_view(app->hid_keyboard), hid_exit_confirm_view); @@ -216,6 +236,8 @@ void hid_free(Hid* app) { dialog_ex_free(app->dialog); view_dispatcher_remove_view(app->view_dispatcher, HidViewKeynote); hid_keynote_free(app->hid_keynote); + view_dispatcher_remove_view(app->view_dispatcher, HidViewKeynoteVertical); + hid_keynote_vertical_free(app->hid_keynote_vertical); view_dispatcher_remove_view(app->view_dispatcher, HidViewKeyboard); hid_keyboard_free(app->hid_keyboard); view_dispatcher_remove_view(app->view_dispatcher, HidViewMedia); diff --git a/applications/external/hid_app/hid.h b/applications/external/hid_app/hid.h index 1ff42c9406..be9176a289 100644 --- a/applications/external/hid_app/hid.h +++ b/applications/external/hid_app/hid.h @@ -17,6 +17,7 @@ #include #include #include "views/hid_keynote.h" +#include "views/hid_keynote_vertical.h" #include "views/hid_keyboard.h" #include "views/hid_media.h" #include "views/hid_mouse.h" @@ -41,6 +42,7 @@ struct Hid { Submenu* device_type_submenu; DialogEx* dialog; HidKeynote* hid_keynote; + HidKeynoteVertical* hid_keynote_vertical; HidKeyboard* hid_keyboard; HidMedia* hid_media; HidMouse* hid_mouse; @@ -64,4 +66,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/external/hid_app/views.h b/applications/external/hid_app/views.h index 14cfa126f7..81e8d6dbea 100644 --- a/applications/external/hid_app/views.h +++ b/applications/external/hid_app/views.h @@ -1,6 +1,7 @@ typedef enum { HidViewSubmenu, HidViewKeynote, + HidViewKeynoteVertical, HidViewKeyboard, HidViewMedia, HidViewMouse, @@ -8,4 +9,4 @@ typedef enum { BtHidViewTikTok, BtHidViewYTShorts, HidViewExitConfirm, -} HidView; \ No newline at end of file +} HidView; diff --git a/applications/external/hid_app/views/hid_keynote_vertical.c b/applications/external/hid_app/views/hid_keynote_vertical.c new file mode 100644 index 0000000000..7d23038133 --- /dev/null +++ b/applications/external/hid_app/views/hid_keynote_vertical.c @@ -0,0 +1,228 @@ +#include "hid_keynote_vertical.h" +#include +#include "../hid.h" + +#include "hid_icons.h" + +#define TAG "HidKeynoteVertical" + +struct HidKeynoteVertical { + View* view; + Hid* hid; +}; + +typedef struct { + bool left_pressed; + bool up_pressed; + bool right_pressed; + bool down_pressed; + bool ok_pressed; + bool back_pressed; + bool connected; + HidTransport transport; +} HidKeynoteVerticalModel; + +static void + hid_keynote_vertical_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_line(canvas, x, y + 6, x, y - 1); + } else if(dir == CanvasDirectionTopToBottom) { + canvas_draw_line(canvas, x, y - 6, x, y + 1); + } else if(dir == CanvasDirectionRightToLeft) { + canvas_draw_line(canvas, x + 6, y, x - 1, y); + } else if(dir == CanvasDirectionLeftToRight) { + canvas_draw_line(canvas, x - 6, y, x + 1, y); + } +} + +static void hid_keynote_vertical_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + HidKeynoteVerticalModel* 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, "Keynote"); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned( + canvas, 24, 14, AlignLeft, AlignTop, "Vertical Up --->"); + + canvas_draw_icon(canvas, 68, 2, &I_Pin_back_arrow_10x8); + canvas_set_font(canvas, FontSecondary); + elements_multiline_text_aligned(canvas, 127, 3, AlignRight, AlignTop, "Hold to exit"); + + // Up + canvas_draw_icon(canvas, 21, 24, &I_Button_18x18); + if(model->up_pressed) { + elements_slightly_rounded_box(canvas, 24, 26, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_vertical_draw_arrow(canvas, 30, 30, CanvasDirectionBottomToTop); + canvas_set_color(canvas, ColorBlack); + + // Down + canvas_draw_icon(canvas, 21, 45, &I_Button_18x18); + if(model->down_pressed) { + elements_slightly_rounded_box(canvas, 24, 47, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_vertical_draw_arrow(canvas, 30, 55, CanvasDirectionTopToBottom); + canvas_set_color(canvas, ColorBlack); + + // Left + canvas_draw_icon(canvas, 0, 35, &I_Button_18x18); + if(model->left_pressed) { + elements_slightly_rounded_box(canvas, 3, 37, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_vertical_draw_arrow(canvas, 7, 43, CanvasDirectionRightToLeft); + canvas_set_color(canvas, ColorBlack); + + // Right + canvas_draw_icon(canvas, 42, 35, &I_Button_18x18); + if(model->right_pressed) { + elements_slightly_rounded_box(canvas, 45, 37, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + hid_keynote_vertical_draw_arrow(canvas, 53, 43, CanvasDirectionLeftToRight); + canvas_set_color(canvas, ColorBlack); + + // Ok + canvas_draw_icon(canvas, 63, 25, &I_Space_65x18); + if(model->ok_pressed) { + elements_slightly_rounded_box(canvas, 66, 27, 60, 13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9); + elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Space"); + canvas_set_color(canvas, ColorBlack); + + // Back + canvas_draw_icon(canvas, 63, 45, &I_Space_65x18); + if(model->back_pressed) { + elements_slightly_rounded_box(canvas, 66, 47, 60, 13); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8); + elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Back"); +} + +static void + hid_keynote_vertical_process(HidKeynoteVertical* hid_keynote_vertical, InputEvent* event) { + with_view_model( + hid_keynote_vertical->view, + HidKeynoteVerticalModel * model, + { + if(event->type == InputTypePress) { + if(event->key == InputKeyUp) { + model->up_pressed = true; + hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_LEFT_ARROW); + } else if(event->key == InputKeyDown) { + model->down_pressed = true; + hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_RIGHT_ARROW); + } else if(event->key == InputKeyLeft) { + model->left_pressed = true; + hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_DOWN_ARROW); + } else if(event->key == InputKeyRight) { + model->right_pressed = true; + hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_UP_ARROW); + } else if(event->key == InputKeyOk) { + model->ok_pressed = true; + hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_SPACEBAR); + } else if(event->key == InputKeyBack) { + model->back_pressed = true; + } + } else if(event->type == InputTypeRelease) { + if(event->key == InputKeyUp) { + model->up_pressed = false; + hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_LEFT_ARROW); + } else if(event->key == InputKeyDown) { + model->down_pressed = false; + hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_RIGHT_ARROW); + } else if(event->key == InputKeyLeft) { + model->left_pressed = false; + hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_DOWN_ARROW); + } else if(event->key == InputKeyRight) { + model->right_pressed = false; + hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_UP_ARROW); + } else if(event->key == InputKeyOk) { + model->ok_pressed = false; + hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_SPACEBAR); + } else if(event->key == InputKeyBack) { + model->back_pressed = false; + } + } else if(event->type == InputTypeShort) { + if(event->key == InputKeyBack) { + hid_hal_keyboard_press(hid_keynote_vertical->hid, HID_KEYBOARD_DELETE); + hid_hal_keyboard_release(hid_keynote_vertical->hid, HID_KEYBOARD_DELETE); + hid_hal_consumer_key_press(hid_keynote_vertical->hid, HID_CONSUMER_AC_BACK); + hid_hal_consumer_key_release(hid_keynote_vertical->hid, HID_CONSUMER_AC_BACK); + } + } + }, + true); +} + +static bool hid_keynote_vertical_input_callback(InputEvent* event, void* context) { + furi_assert(context); + HidKeynoteVertical* hid_keynote_vertical = context; + bool consumed = false; + + if(event->type == InputTypeLong && event->key == InputKeyBack) { + hid_hal_keyboard_release_all(hid_keynote_vertical->hid); + } else { + hid_keynote_vertical_process(hid_keynote_vertical, event); + consumed = true; + } + + return consumed; +} + +HidKeynoteVertical* hid_keynote_vertical_alloc(Hid* hid) { + HidKeynoteVertical* hid_keynote_vertical = malloc(sizeof(HidKeynoteVertical)); + hid_keynote_vertical->view = view_alloc(); + hid_keynote_vertical->hid = hid; + view_set_context(hid_keynote_vertical->view, hid_keynote_vertical); + view_allocate_model( + hid_keynote_vertical->view, ViewModelTypeLocking, sizeof(HidKeynoteVerticalModel)); + view_set_draw_callback(hid_keynote_vertical->view, hid_keynote_vertical_draw_callback); + view_set_input_callback(hid_keynote_vertical->view, hid_keynote_vertical_input_callback); + + with_view_model( + hid_keynote_vertical->view, + HidKeynoteVerticalModel * model, + { model->transport = hid->transport; }, + true); + + return hid_keynote_vertical; +} + +void hid_keynote_vertical_free(HidKeynoteVertical* hid_keynote_vertical) { + furi_assert(hid_keynote_vertical); + view_free(hid_keynote_vertical->view); + free(hid_keynote_vertical); +} + +View* hid_keynote_vertical_get_view(HidKeynoteVertical* hid_keynote_vertical) { + furi_assert(hid_keynote_vertical); + return hid_keynote_vertical->view; +} + +void hid_keynote_vertical_set_connected_status( + HidKeynoteVertical* hid_keynote_vertical, + bool connected) { + furi_assert(hid_keynote_vertical); + with_view_model( + hid_keynote_vertical->view, + HidKeynoteVerticalModel * model, + { model->connected = connected; }, + true); +} diff --git a/applications/external/hid_app/views/hid_keynote_vertical.h b/applications/external/hid_app/views/hid_keynote_vertical.h new file mode 100644 index 0000000000..bb7134adb4 --- /dev/null +++ b/applications/external/hid_app/views/hid_keynote_vertical.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +typedef struct Hid Hid; +typedef struct HidKeynoteVertical HidKeynoteVertical; + +HidKeynoteVertical* hid_keynote_vertical_alloc(Hid* bt_hid); + +void hid_keynote_vertical_free(HidKeynoteVertical* hid_keynote_vertical); + +View* hid_keynote_vertical_get_view(HidKeynoteVertical* hid_keynote_vertical); + +void hid_keynote_vertical_set_connected_status( + HidKeynoteVertical* hid_keynote_vertical, + bool connected);