Sync system apps --nobuild
@@ -8,11 +8,10 @@ App(
|
||||
"dialogs",
|
||||
],
|
||||
stack_size=2 * 1024,
|
||||
order=20,
|
||||
fap_icon="icons/hex_10px.png",
|
||||
fap_icon="icons/hex_10px.bmp",
|
||||
fap_icon_assets="icons",
|
||||
fap_category="Tools",
|
||||
fap_author="@QtRoS",
|
||||
fap_version="2.0",
|
||||
fap_description="App allows to view various files as HEX.",
|
||||
fap_description="App allows to view various files as HEX",
|
||||
)
|
||||
|
||||
@@ -123,7 +123,7 @@ bool hex_viewer_open_file(void* context, const char* file_path) {
|
||||
// TODO Separate function?
|
||||
if(hex_viewer->model->stream) {
|
||||
buffered_file_stream_close(hex_viewer->model->stream);
|
||||
stream_free(hex_viewer->model->stream); // TODO Check
|
||||
stream_free(hex_viewer->model->stream);
|
||||
hex_viewer->model->file_offset = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,10 @@ HexViewer* hex_viewer_app_alloc() {
|
||||
void hex_viewer_app_free(HexViewer* app) {
|
||||
furi_assert(app);
|
||||
|
||||
if(app->model->stream) buffered_file_stream_close(app->model->stream);
|
||||
if(app->model->stream) {
|
||||
buffered_file_stream_close(app->model->stream);
|
||||
stream_free(app->model->stream);
|
||||
}
|
||||
|
||||
// Scene manager
|
||||
scene_manager_free(app->scene_manager);
|
||||
|
||||
@@ -43,7 +43,6 @@ typedef struct {
|
||||
Stream* stream;
|
||||
} HexViewerModel;
|
||||
|
||||
// TODO Clean
|
||||
typedef struct {
|
||||
HexViewerModel* model;
|
||||
|
||||
|
||||
BIN
applications/system/hex_viewer/icons/hex_10px.bmp
Normal file
|
After Width: | Height: | Size: 102 B |
@@ -13,7 +13,7 @@ void hex_viewer_scene_scroll_on_enter(void* context) {
|
||||
|
||||
TextInput* text_input = app->text_input;
|
||||
|
||||
text_input_set_header_text(text_input, "Scroll to percent (0..100)");
|
||||
text_input_set_header_text(text_input, "Scroll to percentage (0..100)");
|
||||
text_input_set_result_callback(
|
||||
text_input,
|
||||
hex_viewer_scene_scroll_callback,
|
||||
|
||||
@@ -61,7 +61,7 @@ void hex_viewer_startscreen_draw(Canvas* canvas, HexViewerStartscreenModel* mode
|
||||
width,
|
||||
0,
|
||||
ROW_HEIGHT * HEX_VIEWER_LINES_ON_SCREEN,
|
||||
first_line_on_screen, // TODO
|
||||
first_line_on_screen,
|
||||
line_count - (HEX_VIEWER_LINES_ON_SCREEN - 1));
|
||||
}
|
||||
|
||||
@@ -69,6 +69,9 @@ void hex_viewer_startscreen_draw(Canvas* canvas, HexViewerStartscreenModel* mode
|
||||
uint32_t row_iters = model->file_read_bytes / HEX_VIEWER_BYTES_PER_LINE;
|
||||
if(model->file_read_bytes % HEX_VIEWER_BYTES_PER_LINE != 0) row_iters += 1;
|
||||
|
||||
// For the rest of drawing.
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
|
||||
for(uint32_t i = 0; i < row_iters; ++i) {
|
||||
uint32_t bytes_left_per_row = model->file_read_bytes - i * HEX_VIEWER_BYTES_PER_LINE;
|
||||
bytes_left_per_row = MIN(bytes_left_per_row, HEX_VIEWER_BYTES_PER_LINE);
|
||||
@@ -79,13 +82,13 @@ void hex_viewer_startscreen_draw(Canvas* canvas, HexViewerStartscreenModel* mode
|
||||
for(uint32_t j = 0; j < bytes_left_per_row; ++j)
|
||||
if(!isprint((int)temp_buf[j])) temp_buf[j] = '.';
|
||||
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
//canvas_set_font(canvas, FontKeyboard);
|
||||
canvas_draw_str(canvas, LEFT_OFFSET, TOP_OFFSET + i * ROW_HEIGHT, temp_buf);
|
||||
} else {
|
||||
uint32_t addr = model->file_offset + i * HEX_VIEWER_BYTES_PER_LINE;
|
||||
snprintf(temp_buf, 32, "%04lX", addr);
|
||||
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
//canvas_set_font(canvas, FontKeyboard);
|
||||
canvas_draw_str(canvas, LEFT_OFFSET, TOP_OFFSET + i * ROW_HEIGHT, temp_buf);
|
||||
}
|
||||
|
||||
@@ -93,7 +96,7 @@ void hex_viewer_startscreen_draw(Canvas* canvas, HexViewerStartscreenModel* mode
|
||||
for(uint32_t j = 0; j < bytes_left_per_row; ++j)
|
||||
p += snprintf(p, 32, "%02X ", model->file_bytes[i][j]);
|
||||
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
//canvas_set_font(canvas, FontKeyboard);
|
||||
canvas_draw_str(canvas, LEFT_OFFSET + 41, TOP_OFFSET + i * ROW_HEIGHT, temp_buf);
|
||||
}
|
||||
|
||||
@@ -125,7 +128,7 @@ bool hex_viewer_startscreen_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
HexViewerStartscreen* instance = context;
|
||||
HexViewer* app = instance->context; // TO so good, but works
|
||||
// TODO InputTypeShort?
|
||||
|
||||
if(event->type == InputTypeRelease || event->type == InputTypeRepeat) {
|
||||
switch(event->key) {
|
||||
case InputKeyBack:
|
||||
|
||||
@@ -4,8 +4,6 @@ App(
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="hid_usb_app",
|
||||
stack_size=1 * 1024,
|
||||
fap_description="Use Flipper as a HID remote control over USB",
|
||||
fap_version="1.0",
|
||||
fap_category="USB",
|
||||
fap_icon="hid_usb_10px.png",
|
||||
fap_icon_assets="assets",
|
||||
@@ -19,8 +17,6 @@ App(
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="hid_ble_app",
|
||||
stack_size=1 * 1024,
|
||||
fap_description="Use Flipper as a HID remote control over Bluetooth",
|
||||
fap_version="1.0",
|
||||
fap_category="Bluetooth",
|
||||
fap_icon="hid_ble_10px.png",
|
||||
fap_icon_assets="assets",
|
||||
|
||||
BIN
applications/system/hid_app/assets/BrokenButton_15x15.png
Normal file
|
After Width: | Height: | Size: 340 B |
BIN
applications/system/hid_app/assets/BtnBackV_9x9.png
Normal file
|
After Width: | Height: | Size: 362 B |
BIN
applications/system/hid_app/assets/BtnLeft_9x9.png
Normal file
|
After Width: | Height: | Size: 362 B |
BIN
applications/system/hid_app/assets/Hand_8x10.png
Normal file
|
After Width: | Height: | Size: 156 B |
BIN
applications/system/hid_app/assets/Help_exit_64x9.png
Normal file
|
After Width: | Height: | Size: 404 B |
BIN
applications/system/hid_app/assets/Help_top_64x17.png
Normal file
|
After Width: | Height: | Size: 470 B |
BIN
applications/system/hid_app/assets/Hold_15x5.png
Normal file
|
After Width: | Height: | Size: 356 B |
BIN
applications/system/hid_app/assets/Mic_7x11.png
Normal file
|
After Width: | Height: | Size: 356 B |
BIN
applications/system/hid_app/assets/MicrophoneCrossed_16x16.png
Normal file
|
After Width: | Height: | Size: 341 B |
|
After Width: | Height: | Size: 329 B |
|
After Width: | Height: | Size: 339 B |
|
After Width: | Height: | Size: 323 B |
BIN
applications/system/hid_app/assets/for_help_27x5.png
Normal file
|
After Width: | Height: | Size: 162 B |
@@ -12,11 +12,11 @@ enum HidDebugSubmenuIndex {
|
||||
HidSubmenuIndexNumpad,
|
||||
HidSubmenuIndexMedia,
|
||||
HidSubmenuIndexMovie,
|
||||
HidSubmenuIndexTikTok,
|
||||
HidSubmenuIndexTikShorts,
|
||||
HidSubmenuIndexMouse,
|
||||
HidSubmenuIndexMouseClicker,
|
||||
HidSubmenuIndexMouseJiggler,
|
||||
HidSubmenuIndexPtt,
|
||||
HidSubmenuIndexPushToTalk,
|
||||
};
|
||||
|
||||
static void hid_submenu_callback(void* context, uint32_t index) {
|
||||
@@ -45,18 +45,18 @@ static void hid_submenu_callback(void* context, uint32_t index) {
|
||||
} 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);
|
||||
} else if(index == HidSubmenuIndexPushToTalk) {
|
||||
app->view_id = HidViewPushToTalkMenu;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewPushToTalkMenu);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con
|
||||
hid_mouse_clicker_set_connected_status(hid->hid_mouse_clicker, connected);
|
||||
hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected);
|
||||
hid_ptt_set_connected_status(hid->hid_ptt, connected);
|
||||
hid_tiktok_set_connected_status(hid->hid_tiktok, connected);
|
||||
hid_tikshorts_set_connected_status(hid->hid_tikshorts, connected);
|
||||
}
|
||||
|
||||
static uint32_t hid_menu_view(void* context) {
|
||||
@@ -93,6 +93,11 @@ static uint32_t hid_exit(void* context) {
|
||||
return VIEW_NONE;
|
||||
}
|
||||
|
||||
static uint32_t hid_ptt_menu_view(void* context) {
|
||||
UNUSED(context);
|
||||
return HidViewPushToTalkMenu;
|
||||
}
|
||||
|
||||
Hid* hid_alloc(HidTransport transport) {
|
||||
Hid* app = malloc(sizeof(Hid));
|
||||
app->transport = transport;
|
||||
@@ -134,7 +139,7 @@ Hid* hid_alloc(HidTransport transport) {
|
||||
submenu_add_item(
|
||||
app->device_type_submenu,
|
||||
"TikTok / YT Shorts",
|
||||
HidSubmenuIndexTikTok,
|
||||
HidSubmenuIndexTikShorts,
|
||||
hid_submenu_callback,
|
||||
app);
|
||||
}
|
||||
@@ -151,7 +156,11 @@ Hid* hid_alloc(HidTransport transport) {
|
||||
hid_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
app->device_type_submenu, "PTT", HidSubmenuIndexPtt, hid_submenu_callback, app);
|
||||
app->device_type_submenu,
|
||||
"PushToTalk",
|
||||
HidSubmenuIndexPushToTalk,
|
||||
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));
|
||||
@@ -163,7 +172,6 @@ Hid* hid_alloc(HidTransport transport) {
|
||||
Hid* hid_app_alloc_view(void* context) {
|
||||
furi_assert(context);
|
||||
Hid* app = context;
|
||||
// Dialog view
|
||||
|
||||
// Keynote view
|
||||
app->hid_keynote = hid_keynote_alloc(app);
|
||||
@@ -195,11 +203,11 @@ Hid* hid_app_alloc_view(void* context) {
|
||||
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_menu_view);
|
||||
// TikTok / YT Shorts view
|
||||
app->hid_tikshorts = hid_tikshorts_alloc(app);
|
||||
view_set_previous_callback(hid_tikshorts_get_view(app->hid_tikshorts), hid_menu_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);
|
||||
@@ -223,10 +231,15 @@ Hid* hid_app_alloc_view(void* context) {
|
||||
HidViewMouseJiggler,
|
||||
hid_mouse_jiggler_get_view(app->hid_mouse_jiggler));
|
||||
|
||||
// Ptt view
|
||||
// PushToTalk view
|
||||
app->hid_ptt_menu = hid_ptt_menu_alloc(app);
|
||||
view_set_previous_callback(hid_ptt_menu_get_view(app->hid_ptt_menu), hid_menu_view);
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, HidViewPushToTalkMenu, hid_ptt_menu_get_view(app->hid_ptt_menu));
|
||||
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));
|
||||
view_set_previous_callback(hid_ptt_get_view(app->hid_ptt), hid_ptt_menu_view);
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, HidViewPushToTalk, hid_ptt_get_view(app->hid_ptt));
|
||||
|
||||
return app;
|
||||
}
|
||||
@@ -258,10 +271,12 @@ void hid_free(Hid* app) {
|
||||
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, HidViewPtt);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, HidViewPushToTalkMenu);
|
||||
hid_ptt_menu_free(app->hid_ptt_menu);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, HidViewPushToTalk);
|
||||
hid_ptt_free(app->hid_ptt);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok);
|
||||
hid_tiktok_free(app->hid_tiktok);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikShorts);
|
||||
hid_tikshorts_free(app->hid_tikshorts);
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
|
||||
// Close records
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
#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"
|
||||
#include "views/hid_ptt_menu.h"
|
||||
|
||||
#include <assets_icons.h>
|
||||
|
||||
@@ -51,8 +52,9 @@ struct Hid {
|
||||
HidMouse* hid_mouse;
|
||||
HidMouseClicker* hid_mouse_clicker;
|
||||
HidMouseJiggler* hid_mouse_jiggler;
|
||||
HidTikTok* hid_tiktok;
|
||||
HidPtt* hid_ptt;
|
||||
HidTikShorts* hid_tikshorts;
|
||||
HidPushToTalk* hid_ptt;
|
||||
HidPushToTalkMenu* hid_ptt_menu;
|
||||
|
||||
HidTransport transport;
|
||||
uint32_t view_id;
|
||||
|
||||
@@ -8,6 +8,8 @@ typedef enum {
|
||||
HidViewMouse,
|
||||
HidViewMouseClicker,
|
||||
HidViewMouseJiggler,
|
||||
BtHidViewTikTok,
|
||||
HidViewPtt,
|
||||
BtHidViewTikShorts,
|
||||
HidViewPushToTalk,
|
||||
HidViewPushToTalkMenu,
|
||||
HidViewPushToTalkHelp,
|
||||
} HidView;
|
||||
|
||||
@@ -188,12 +188,15 @@ static bool hid_media_input_callback(InputEvent* event, void* context) {
|
||||
HidMedia* hid_media = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == InputTypePress) {
|
||||
hid_media_process_press(hid_media, event);
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
hid_media_process_release(hid_media, event);
|
||||
if(event->type == InputTypeLong && event->key == InputKeyBack) {
|
||||
hid_hal_keyboard_release_all(hid_media->hid);
|
||||
} else {
|
||||
consumed = true;
|
||||
if(event->type == InputTypePress) {
|
||||
hid_media_process_press(hid_media, event);
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
hid_media_process_release(hid_media, event);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
@@ -186,13 +186,19 @@ static bool hid_movie_input_callback(InputEvent* event, void* 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);
|
||||
if(event->type == InputTypeLong && event->key == InputKeyBack) {
|
||||
hid_hal_keyboard_release_all(hid_movie->hid);
|
||||
} else {
|
||||
consumed = true;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,17 @@
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct Hid Hid;
|
||||
typedef struct HidPtt HidPtt;
|
||||
typedef struct HidPushToTalk HidPushToTalk;
|
||||
|
||||
HidPtt* hid_ptt_alloc(Hid* bt_hid);
|
||||
HidPushToTalk* hid_ptt_alloc(Hid* bt_hid);
|
||||
|
||||
void hid_ptt_free(HidPtt* hid_ptt);
|
||||
void hid_ptt_free(HidPushToTalk* hid_ptt);
|
||||
|
||||
View* hid_ptt_get_view(HidPtt* hid_ptt);
|
||||
View* hid_ptt_get_view(HidPushToTalk* hid_ptt);
|
||||
|
||||
void hid_ptt_set_connected_status(HidPtt* hid_ptt, bool connected);
|
||||
void hid_ptt_set_connected_status(HidPushToTalk* hid_ptt, bool connected);
|
||||
|
||||
enum HidPushToTalkOSes {
|
||||
HidPushToTalkMacOS,
|
||||
HidPushToTalkLinux,
|
||||
};
|
||||
|
||||
423
applications/system/hid_app/views/hid_ptt_menu.c
Normal file
@@ -0,0 +1,423 @@
|
||||
#include "hid_ptt_menu.h"
|
||||
#include "hid_ptt.h"
|
||||
#include <gui/elements.h>
|
||||
#include <m-array.h>
|
||||
#include "../hid.h"
|
||||
#include "../views.h"
|
||||
|
||||
#define TAG "HidPushToTalkMenu"
|
||||
|
||||
struct HidPushToTalkMenu {
|
||||
View* view;
|
||||
Hid* hid;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
FuriString* label;
|
||||
uint32_t index;
|
||||
PushToTalkMenuItemCallback callback;
|
||||
void* callback_context;
|
||||
} PushToTalkMenuItem;
|
||||
|
||||
// Menu item
|
||||
static void PushToTalkMenuItem_init(PushToTalkMenuItem* item) {
|
||||
item->label = furi_string_alloc();
|
||||
item->index = 0;
|
||||
}
|
||||
|
||||
static void PushToTalkMenuItem_init_set(PushToTalkMenuItem* item, const PushToTalkMenuItem* src) {
|
||||
item->label = furi_string_alloc_set(src->label);
|
||||
item->index = src->index;
|
||||
}
|
||||
|
||||
static void PushToTalkMenuItem_set(PushToTalkMenuItem* item, const PushToTalkMenuItem* src) {
|
||||
furi_string_set(item->label, src->label);
|
||||
item->index = src->index;
|
||||
}
|
||||
|
||||
static void PushToTalkMenuItem_clear(PushToTalkMenuItem* item) {
|
||||
furi_string_free(item->label);
|
||||
}
|
||||
|
||||
ARRAY_DEF(
|
||||
PushToTalkMenuItemArray,
|
||||
PushToTalkMenuItem,
|
||||
(INIT(API_2(PushToTalkMenuItem_init)),
|
||||
SET(API_6(PushToTalkMenuItem_set)),
|
||||
INIT_SET(API_6(PushToTalkMenuItem_init_set)),
|
||||
CLEAR(API_2(PushToTalkMenuItem_clear))))
|
||||
|
||||
// Menu list (horisontal, 2d array)
|
||||
typedef struct {
|
||||
FuriString* label;
|
||||
uint32_t index;
|
||||
PushToTalkMenuItemArray_t items;
|
||||
} PushToTalkMenuList;
|
||||
|
||||
typedef struct {
|
||||
size_t list_position;
|
||||
size_t position;
|
||||
size_t window_position;
|
||||
PushToTalkMenuList* lists;
|
||||
int lists_count;
|
||||
} HidPushToTalkMenuModel;
|
||||
|
||||
static void
|
||||
hid_ptt_menu_draw_list(Canvas* canvas, void* context, const PushToTalkMenuItemArray_t items) {
|
||||
furi_assert(context);
|
||||
HidPushToTalkMenuModel* model = context;
|
||||
const uint8_t item_height = 16;
|
||||
uint8_t item_width = canvas_width(canvas) - 5;
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
size_t position = 0;
|
||||
PushToTalkMenuItemArray_it_t it;
|
||||
for(PushToTalkMenuItemArray_it(it, items); !PushToTalkMenuItemArray_end_p(it);
|
||||
PushToTalkMenuItemArray_next(it)) {
|
||||
const size_t item_position = position - model->window_position;
|
||||
const size_t items_on_screen = 3;
|
||||
uint8_t y_offset = 16;
|
||||
|
||||
if(item_position < items_on_screen) {
|
||||
if(position == model->position) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
elements_slightly_rounded_box(
|
||||
canvas,
|
||||
0,
|
||||
y_offset + (item_position * item_height) + 1,
|
||||
item_width,
|
||||
item_height - 2);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
} else {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
}
|
||||
|
||||
FuriString* disp_str;
|
||||
disp_str = furi_string_alloc_set(PushToTalkMenuItemArray_cref(it)->label);
|
||||
elements_string_fit_width(canvas, disp_str, item_width - (6 * 2));
|
||||
|
||||
canvas_draw_str(
|
||||
canvas,
|
||||
6,
|
||||
y_offset + (item_position * item_height) + item_height - 4,
|
||||
furi_string_get_cstr(disp_str));
|
||||
|
||||
furi_string_free(disp_str);
|
||||
}
|
||||
|
||||
position++;
|
||||
}
|
||||
elements_scrollbar_pos(
|
||||
canvas, 128, 17, 46, model->position, PushToTalkMenuItemArray_size(items));
|
||||
}
|
||||
|
||||
PushToTalkMenuList* hid_ptt_menu_get_list_at_index(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
HidPushToTalkMenuModel* model = context;
|
||||
for(int i = 0; i < model->lists_count; i++) {
|
||||
PushToTalkMenuList* list = &model->lists[i];
|
||||
if(index == list->index) {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void hid_ptt_menu_draw_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
HidPushToTalkMenuModel* model = context;
|
||||
if(model->lists_count == 0) {
|
||||
return;
|
||||
}
|
||||
uint8_t item_width = canvas_width(canvas) - 5;
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 4, 11, "<");
|
||||
canvas_draw_str(canvas, 121, 11, ">");
|
||||
|
||||
PushToTalkMenuList* list = &model->lists[model->list_position];
|
||||
FuriString* disp_str;
|
||||
disp_str = furi_string_alloc_set(list->label);
|
||||
elements_string_fit_width(canvas, disp_str, item_width - (6 * 2));
|
||||
uint8_t x_pos =
|
||||
(canvas_width(canvas) - canvas_string_width(canvas, furi_string_get_cstr(disp_str))) / 2;
|
||||
canvas_draw_str(canvas, x_pos, 11, furi_string_get_cstr(disp_str));
|
||||
furi_string_free(disp_str);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
hid_ptt_menu_draw_list(canvas, context, list->items);
|
||||
}
|
||||
|
||||
void ptt_menu_add_list(HidPushToTalkMenu* hid_ptt_menu, const char* label, uint32_t index) {
|
||||
furi_assert(label);
|
||||
furi_assert(hid_ptt_menu);
|
||||
with_view_model(
|
||||
hid_ptt_menu->view,
|
||||
HidPushToTalkMenuModel * model,
|
||||
{
|
||||
if(model->lists_count == 0) {
|
||||
model->lists = (PushToTalkMenuList*)malloc(sizeof(PushToTalkMenuList));
|
||||
} else {
|
||||
model->lists = (PushToTalkMenuList*)realloc(
|
||||
model->lists, (model->lists_count + 1) * sizeof(PushToTalkMenuList));
|
||||
}
|
||||
if(model->lists == NULL) {
|
||||
FURI_LOG_E(TAG, "Memory reallocation failed (%i)", model->lists_count);
|
||||
return;
|
||||
}
|
||||
PushToTalkMenuList* list = &model->lists[model->lists_count];
|
||||
PushToTalkMenuItemArray_init(list->items);
|
||||
list->label = furi_string_alloc_set(label);
|
||||
list->index = index;
|
||||
model->lists_count += 1;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void ptt_menu_add_item_to_list(
|
||||
HidPushToTalkMenu* hid_ptt_menu,
|
||||
uint32_t list_index,
|
||||
const char* label,
|
||||
uint32_t index,
|
||||
PushToTalkMenuItemCallback callback,
|
||||
void* callback_context) {
|
||||
PushToTalkMenuItem* item = NULL;
|
||||
furi_assert(label);
|
||||
furi_assert(hid_ptt_menu);
|
||||
UNUSED(list_index);
|
||||
with_view_model(
|
||||
hid_ptt_menu->view,
|
||||
HidPushToTalkMenuModel * model,
|
||||
{
|
||||
PushToTalkMenuList* list = hid_ptt_menu_get_list_at_index(model, list_index);
|
||||
if(list == NULL) {
|
||||
FURI_LOG_E(TAG, "Adding item %s to unknown index %li", label, list_index);
|
||||
return;
|
||||
}
|
||||
item = PushToTalkMenuItemArray_push_new(list->items);
|
||||
furi_string_set_str(item->label, label);
|
||||
item->index = index;
|
||||
item->callback = callback;
|
||||
item->callback_context = callback_context;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void ptt_menu_shift_list(HidPushToTalkMenu* hid_ptt_menu, int shift) {
|
||||
size_t new_position = 0;
|
||||
uint32_t index = 0;
|
||||
with_view_model(
|
||||
hid_ptt_menu->view,
|
||||
HidPushToTalkMenuModel * model,
|
||||
{
|
||||
int new_list_position = (short)model->list_position + shift;
|
||||
if(new_list_position >= model->lists_count) {
|
||||
new_list_position = 0;
|
||||
} else if(new_list_position < 0) {
|
||||
new_list_position = model->lists_count - 1;
|
||||
}
|
||||
PushToTalkMenuList* list = &model->lists[model->list_position];
|
||||
PushToTalkMenuList* new_list = &model->lists[new_list_position];
|
||||
size_t new_window_position = model->window_position;
|
||||
const size_t items_size = PushToTalkMenuItemArray_size(new_list->items);
|
||||
size_t position = 0;
|
||||
// Find item index from current list
|
||||
PushToTalkMenuItemArray_it_t it;
|
||||
for(PushToTalkMenuItemArray_it(it, list->items); !PushToTalkMenuItemArray_end_p(it);
|
||||
PushToTalkMenuItemArray_next(it)) {
|
||||
if(position == model->position) {
|
||||
index = PushToTalkMenuItemArray_cref(it)->index;
|
||||
break;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
// Try to find item with the same index in a new list
|
||||
position = 0;
|
||||
bool item_exists_in_new_list = false;
|
||||
for(PushToTalkMenuItemArray_it(it, new_list->items);
|
||||
!PushToTalkMenuItemArray_end_p(it);
|
||||
PushToTalkMenuItemArray_next(it)) {
|
||||
if(PushToTalkMenuItemArray_cref(it)->index == index) {
|
||||
item_exists_in_new_list = true;
|
||||
new_position = position;
|
||||
break;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
|
||||
// This list item is not presented in a new list, let's try to keep position as is.
|
||||
// If it's out of range for the new list set it to the end
|
||||
if(!item_exists_in_new_list) {
|
||||
new_position = items_size - 1 < model->position ? items_size - 1 : model->position;
|
||||
}
|
||||
|
||||
// Tune window position. As we have 3 items on screen, keep focus centered
|
||||
const size_t items_on_screen = 3;
|
||||
|
||||
if(new_position >= items_size - 1) {
|
||||
if(items_size < items_on_screen + 1) {
|
||||
new_window_position = 0;
|
||||
} else {
|
||||
new_window_position = items_size - items_on_screen;
|
||||
}
|
||||
} else if(new_position < items_on_screen - 1) {
|
||||
new_window_position = 0;
|
||||
} else {
|
||||
new_window_position = new_position - 1;
|
||||
}
|
||||
model->list_position = new_list_position;
|
||||
model->position = new_position;
|
||||
model->window_position = new_window_position;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void ptt_menu_process_up(HidPushToTalkMenu* hid_ptt_menu) {
|
||||
with_view_model(
|
||||
hid_ptt_menu->view,
|
||||
HidPushToTalkMenuModel * model,
|
||||
{
|
||||
PushToTalkMenuList* list = &model->lists[model->list_position];
|
||||
const size_t items_on_screen = 3;
|
||||
const size_t items_size = PushToTalkMenuItemArray_size(list->items);
|
||||
|
||||
if(model->position > 0) {
|
||||
model->position--;
|
||||
if((model->position == model->window_position) && (model->window_position > 0)) {
|
||||
model->window_position--;
|
||||
}
|
||||
} else {
|
||||
model->position = items_size - 1;
|
||||
if(model->position > items_on_screen - 1) {
|
||||
model->window_position = model->position - (items_on_screen - 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void ptt_menu_process_down(HidPushToTalkMenu* hid_ptt_menu) {
|
||||
with_view_model(
|
||||
hid_ptt_menu->view,
|
||||
HidPushToTalkMenuModel * model,
|
||||
{
|
||||
PushToTalkMenuList* list = &model->lists[model->list_position];
|
||||
const size_t items_on_screen = 3;
|
||||
const size_t items_size = PushToTalkMenuItemArray_size(list->items);
|
||||
|
||||
if(model->position < items_size - 1) {
|
||||
model->position++;
|
||||
if((model->position - model->window_position > items_on_screen - 2) &&
|
||||
(model->window_position < items_size - items_on_screen)) {
|
||||
model->window_position++;
|
||||
}
|
||||
} else {
|
||||
model->position = 0;
|
||||
model->window_position = 0;
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void ptt_menu_process_ok(HidPushToTalkMenu* hid_ptt_menu) {
|
||||
PushToTalkMenuList* list = NULL;
|
||||
PushToTalkMenuItem* item = NULL;
|
||||
with_view_model(
|
||||
hid_ptt_menu->view,
|
||||
HidPushToTalkMenuModel * model,
|
||||
{
|
||||
list = &model->lists[model->list_position];
|
||||
const size_t items_size = PushToTalkMenuItemArray_size(list->items);
|
||||
if(model->position < items_size) {
|
||||
item = PushToTalkMenuItemArray_get(list->items, model->position);
|
||||
}
|
||||
},
|
||||
true);
|
||||
if(item && list && item->callback) {
|
||||
item->callback(item->callback_context, list->index, list->label, item->index, item->label);
|
||||
}
|
||||
}
|
||||
|
||||
static bool hid_ptt_menu_input_callback(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
HidPushToTalkMenu* hid_ptt_menu = context;
|
||||
bool consumed = false;
|
||||
if(event->type == InputTypeShort) {
|
||||
switch(event->key) {
|
||||
case InputKeyUp:
|
||||
consumed = true;
|
||||
ptt_menu_process_up(hid_ptt_menu);
|
||||
break;
|
||||
case InputKeyDown:
|
||||
consumed = true;
|
||||
ptt_menu_process_down(hid_ptt_menu);
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
consumed = true;
|
||||
ptt_menu_shift_list(hid_ptt_menu, -1);
|
||||
break;
|
||||
case InputKeyRight:
|
||||
consumed = true;
|
||||
ptt_menu_shift_list(hid_ptt_menu, +1);
|
||||
break;
|
||||
case InputKeyOk:
|
||||
consumed = true;
|
||||
ptt_menu_process_ok(hid_ptt_menu);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(event->type == InputTypeRepeat) {
|
||||
if(event->key == InputKeyUp) {
|
||||
consumed = true;
|
||||
ptt_menu_process_up(hid_ptt_menu);
|
||||
} else if(event->key == InputKeyDown) {
|
||||
consumed = true;
|
||||
ptt_menu_process_down(hid_ptt_menu);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
View* hid_ptt_menu_get_view(HidPushToTalkMenu* hid_ptt_menu) {
|
||||
furi_assert(hid_ptt_menu);
|
||||
return hid_ptt_menu->view;
|
||||
}
|
||||
|
||||
HidPushToTalkMenu* hid_ptt_menu_alloc(Hid* hid) {
|
||||
HidPushToTalkMenu* hid_ptt_menu = malloc(sizeof(HidPushToTalkMenu));
|
||||
hid_ptt_menu->hid = hid;
|
||||
hid_ptt_menu->view = view_alloc();
|
||||
view_set_context(hid_ptt_menu->view, hid_ptt_menu);
|
||||
view_allocate_model(hid_ptt_menu->view, ViewModelTypeLocking, sizeof(HidPushToTalkMenuModel));
|
||||
view_set_draw_callback(hid_ptt_menu->view, hid_ptt_menu_draw_callback);
|
||||
view_set_input_callback(hid_ptt_menu->view, hid_ptt_menu_input_callback);
|
||||
|
||||
with_view_model(
|
||||
hid_ptt_menu->view,
|
||||
HidPushToTalkMenuModel * model,
|
||||
{
|
||||
model->lists_count = 0;
|
||||
model->position = 0;
|
||||
model->window_position = 0;
|
||||
},
|
||||
true);
|
||||
return hid_ptt_menu;
|
||||
}
|
||||
|
||||
void hid_ptt_menu_free(HidPushToTalkMenu* hid_ptt_menu) {
|
||||
furi_assert(hid_ptt_menu);
|
||||
with_view_model(
|
||||
hid_ptt_menu->view,
|
||||
HidPushToTalkMenuModel * model,
|
||||
{
|
||||
for(int i = 0; i < model->lists_count; i++) {
|
||||
PushToTalkMenuItemArray_clear(model->lists[i].items);
|
||||
furi_string_free(model->lists[i].label);
|
||||
}
|
||||
free(model->lists);
|
||||
},
|
||||
true);
|
||||
view_free(hid_ptt_menu->view);
|
||||
free(hid_ptt_menu);
|
||||
}
|
||||
29
applications/system/hid_app/views/hid_ptt_menu.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct Hid Hid;
|
||||
typedef struct HidPushToTalkMenu HidPushToTalkMenu;
|
||||
|
||||
typedef void (*PushToTalkMenuItemCallback)(
|
||||
void* context,
|
||||
uint32_t listIndex,
|
||||
FuriString* listLabel,
|
||||
uint32_t itemIndex,
|
||||
FuriString* itemLabel);
|
||||
|
||||
HidPushToTalkMenu* hid_ptt_menu_alloc(Hid* bt_hid);
|
||||
|
||||
void hid_ptt_menu_free(HidPushToTalkMenu* hid_ptt_menu);
|
||||
|
||||
View* hid_ptt_menu_get_view(HidPushToTalkMenu* hid_ptt_menu);
|
||||
|
||||
void ptt_menu_add_item_to_list(
|
||||
HidPushToTalkMenu* hid_ptt_menu,
|
||||
uint32_t list_index,
|
||||
const char* label,
|
||||
uint32_t index,
|
||||
PushToTalkMenuItemCallback callback,
|
||||
void* callback_context);
|
||||
|
||||
void ptt_menu_add_list(HidPushToTalkMenu* hid_ptt_menu, const char* label, uint32_t index);
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "hid_tiktok.h"
|
||||
#include "hid_tikshorts.h"
|
||||
#include "../hid.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
#include "hid_icons.h"
|
||||
|
||||
#define TAG "HidTikTok"
|
||||
#define TAG "HidTikShorts"
|
||||
|
||||
struct HidTikTok {
|
||||
struct HidTikShorts {
|
||||
View* view;
|
||||
Hid* hid;
|
||||
};
|
||||
@@ -21,11 +21,11 @@ typedef struct {
|
||||
bool is_cursor_set;
|
||||
bool back_mouse_pressed;
|
||||
HidTransport transport;
|
||||
} HidTikTokModel;
|
||||
} HidTikShortsModel;
|
||||
|
||||
static void hid_tiktok_draw_callback(Canvas* canvas, void* context) {
|
||||
static void hid_tikshorts_draw_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
HidTikTokModel* model = context;
|
||||
HidTikShortsModel* model = context;
|
||||
|
||||
// Header
|
||||
if(model->transport == HidTransportBle) {
|
||||
@@ -110,30 +110,32 @@ static void hid_tiktok_draw_callback(Canvas* canvas, void* context) {
|
||||
elements_multiline_text_aligned(canvas, 13, 62, AlignLeft, AlignBottom, "Hold to exit");
|
||||
}
|
||||
|
||||
static void hid_tiktok_reset_cursor(HidTikTok* hid_tiktok) {
|
||||
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_tiktok->hid, -127, -127);
|
||||
hid_hal_mouse_move(hid_tikshorts->hid, -127, -127);
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
// Move cursor from the corner
|
||||
hid_hal_mouse_move(hid_tiktok->hid, 20, 120);
|
||||
hid_hal_mouse_move(hid_tikshorts->hid, 20, 120);
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
|
||||
static void
|
||||
hid_tiktok_process_press(HidTikTok* hid_tiktok, HidTikTokModel* model, InputEvent* event) {
|
||||
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_tiktok->hid, HID_CONSUMER_VOLUME_DECREMENT);
|
||||
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_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT);
|
||||
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) {
|
||||
@@ -141,18 +143,20 @@ static void
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hid_tiktok_process_release(HidTikTok* hid_tiktok, HidTikTokModel* model, InputEvent* event) {
|
||||
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_tiktok->hid, HID_CONSUMER_VOLUME_DECREMENT);
|
||||
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_tiktok->hid, HID_CONSUMER_VOLUME_INCREMENT);
|
||||
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) {
|
||||
@@ -160,61 +164,61 @@ static void
|
||||
}
|
||||
}
|
||||
|
||||
static bool hid_tiktok_input_callback(InputEvent* event, void* context) {
|
||||
static bool hid_tikshorts_input_callback(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
HidTikTok* hid_tiktok = context;
|
||||
HidTikShorts* hid_tikshorts = context;
|
||||
bool consumed = false;
|
||||
|
||||
with_view_model(
|
||||
hid_tiktok->view,
|
||||
HidTikTokModel * model,
|
||||
hid_tikshorts->view,
|
||||
HidTikShortsModel * model,
|
||||
{
|
||||
if(event->type == InputTypePress) {
|
||||
hid_tiktok_process_press(hid_tiktok, model, event);
|
||||
hid_tikshorts_process_press(hid_tikshorts, model, event);
|
||||
if(model->connected && !model->is_cursor_set) {
|
||||
hid_tiktok_reset_cursor(hid_tiktok);
|
||||
hid_tikshorts_reset_cursor(hid_tikshorts);
|
||||
model->is_cursor_set = true;
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
hid_tiktok_process_release(hid_tiktok, model, event);
|
||||
hid_tikshorts_process_release(hid_tikshorts, model, event);
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyOk) {
|
||||
hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
||||
hid_hal_mouse_press(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(25);
|
||||
hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
||||
hid_hal_mouse_release(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(100);
|
||||
hid_hal_mouse_press(hid_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
||||
hid_hal_mouse_press(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(25);
|
||||
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, -8);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -10);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -8);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, -6);
|
||||
hid_hal_mouse_release(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
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, 8);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, 10);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, 8);
|
||||
hid_hal_mouse_scroll(hid_tiktok->hid, 6);
|
||||
// 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_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
||||
hid_hal_mouse_press(hid_tikshorts->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(50);
|
||||
hid_hal_mouse_release(hid_tiktok->hid, HID_MOUSE_BTN_LEFT);
|
||||
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_tiktok->hid);
|
||||
hid_hal_consumer_key_release_all(hid_tikshorts->hid);
|
||||
model->is_cursor_set = false;
|
||||
consumed = false;
|
||||
}
|
||||
@@ -225,37 +229,40 @@ static bool hid_tiktok_input_callback(InputEvent* event, void* context) {
|
||||
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);
|
||||
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_tiktok->view, HidTikTokModel * model, { model->transport = bt_hid->transport; }, true);
|
||||
hid_tikshorts->view,
|
||||
HidTikShortsModel * model,
|
||||
{ model->transport = bt_hid->transport; },
|
||||
true);
|
||||
|
||||
return hid_tiktok;
|
||||
return hid_tikshorts;
|
||||
}
|
||||
|
||||
void hid_tiktok_free(HidTikTok* hid_tiktok) {
|
||||
furi_assert(hid_tiktok);
|
||||
view_free(hid_tiktok->view);
|
||||
free(hid_tiktok);
|
||||
void hid_tikshorts_free(HidTikShorts* hid_tikshorts) {
|
||||
furi_assert(hid_tikshorts);
|
||||
view_free(hid_tikshorts->view);
|
||||
free(hid_tikshorts);
|
||||
}
|
||||
|
||||
View* hid_tiktok_get_view(HidTikTok* hid_tiktok) {
|
||||
furi_assert(hid_tiktok);
|
||||
return hid_tiktok->view;
|
||||
View* hid_tikshorts_get_view(HidTikShorts* hid_tikshorts) {
|
||||
furi_assert(hid_tikshorts);
|
||||
return hid_tikshorts->view;
|
||||
}
|
||||
|
||||
void hid_tiktok_set_connected_status(HidTikTok* hid_tiktok, bool connected) {
|
||||
furi_assert(hid_tiktok);
|
||||
void hid_tikshorts_set_connected_status(HidTikShorts* hid_tikshorts, bool connected) {
|
||||
furi_assert(hid_tikshorts);
|
||||
with_view_model(
|
||||
hid_tiktok->view,
|
||||
HidTikTokModel * model,
|
||||
hid_tikshorts->view,
|
||||
HidTikShortsModel * model,
|
||||
{
|
||||
model->connected = connected;
|
||||
model->is_cursor_set = false;
|
||||
14
applications/system/hid_app/views/hid_tikshorts.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
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);
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
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);
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include "ir_remote_icons.h"
|
||||
#include <ir_remote_icons.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
#include <notification/notification.h>
|
||||
|
||||
@@ -5,6 +5,7 @@ App(
|
||||
entry_point="playlist_app",
|
||||
requires=["storage", "gui", "dialogs", "subghz"],
|
||||
stack_size=2 * 1024,
|
||||
order=14,
|
||||
fap_icon="subplaylist_10px.png",
|
||||
fap_category="Sub-GHz",
|
||||
fap_icon_assets="images",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <storage/storage.h>
|
||||
|
||||
#include <lib/toolbox/path.h>
|
||||
#include "subghz_playlist_icons.h"
|
||||
#include <subghz_playlist_icons.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
#include <lib/subghz/protocols/protocol_items.h>
|
||||
|
||||
@@ -239,7 +239,6 @@ bool subrem_view_remote_input(InputEvent* event, void* context) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// BACK button processing end
|
||||
|
||||
if(event->key == InputKeyUp && event->type == InputTypePress) {
|
||||
|
||||
@@ -8,6 +8,7 @@ App(
|
||||
"dialogs",
|
||||
],
|
||||
stack_size=10 * 1024,
|
||||
order=20,
|
||||
fap_icon="icons/text_10px.png",
|
||||
fap_category="Tools",
|
||||
fap_icon_assets="icons",
|
||||
|
||||