forked from flipperdevices/flipperzero-firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FL-2882] BLE tiktok controller (flipperdevices#1859)
* bt hid: introduce tiktok controller * assets: add bt tiktok assets * bt hid: finish tiktok draw * bt hid: add input process to tiktok view * bt hid: add tiktok swipe emulation * bt hid: fix exit from tiktok controller * ble hid: add delay to emulate double tap * ble hid: change options order * bt hid: build as external application * ble hid: fix naming Co-authored-by: あく <[email protected]>
- Loading branch information
Showing
25 changed files
with
250 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,5 @@ App( | |
provides=[ | ||
"music_player", | ||
"snake_game", | ||
"bt_hid", | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,10 @@ | ||
App( | ||
appid="bt_hid", | ||
name="Bluetooth Remote", | ||
apptype=FlipperAppType.PLUGIN, | ||
apptype=FlipperAppType.EXTERNAL, | ||
entry_point="bt_hid_app", | ||
stack_size=1 * 1024, | ||
cdefines=["APP_BLE_HID"], | ||
requires=[ | ||
"bt", | ||
"gui", | ||
], | ||
order=10, | ||
fap_icon="bt_remote_10px.png", | ||
fap_category="Tools", | ||
fap_icon="bt_remote_10px.png", | ||
fap_icon_assets="assets", | ||
) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
#include "bt_hid_tiktok.h" | ||
#include <furi.h> | ||
#include <furi_hal_bt_hid.h> | ||
#include <furi_hal_usb_hid.h> | ||
#include <gui/elements.h> | ||
|
||
#include "bt_hid_icons.h" | ||
|
||
struct BtHidTikTok { | ||
View* view; | ||
}; | ||
|
||
typedef struct { | ||
bool left_pressed; | ||
bool up_pressed; | ||
bool right_pressed; | ||
bool down_pressed; | ||
bool ok_pressed; | ||
bool connected; | ||
} BtHidTikTokModel; | ||
|
||
static void bt_hid_tiktok_draw_callback(Canvas* canvas, void* context) { | ||
furi_assert(context); | ||
BtHidTikTokModel* model = context; | ||
|
||
// Header | ||
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 bt_hid_tiktok_process_press(BtHidTikTok* bt_hid_tiktok, InputEvent* event) { | ||
with_view_model( | ||
bt_hid_tiktok->view, | ||
BtHidTikTokModel * model, | ||
{ | ||
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; | ||
furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_DECREMENT); | ||
} else if(event->key == InputKeyRight) { | ||
model->right_pressed = true; | ||
furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_INCREMENT); | ||
} else if(event->key == InputKeyOk) { | ||
model->ok_pressed = true; | ||
} | ||
}, | ||
true); | ||
} | ||
|
||
static void bt_hid_tiktok_process_release(BtHidTikTok* bt_hid_tiktok, InputEvent* event) { | ||
with_view_model( | ||
bt_hid_tiktok->view, | ||
BtHidTikTokModel * model, | ||
{ | ||
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; | ||
furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_DECREMENT); | ||
} else if(event->key == InputKeyRight) { | ||
model->right_pressed = false; | ||
furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_INCREMENT); | ||
} else if(event->key == InputKeyOk) { | ||
model->ok_pressed = false; | ||
} | ||
}, | ||
true); | ||
} | ||
|
||
static bool bt_hid_tiktok_input_callback(InputEvent* event, void* context) { | ||
furi_assert(context); | ||
BtHidTikTok* bt_hid_tiktok = context; | ||
bool consumed = false; | ||
|
||
if(event->type == InputTypePress) { | ||
bt_hid_tiktok_process_press(bt_hid_tiktok, event); | ||
consumed = true; | ||
} else if(event->type == InputTypeRelease) { | ||
bt_hid_tiktok_process_release(bt_hid_tiktok, event); | ||
consumed = true; | ||
} else if(event->type == InputTypeShort) { | ||
if(event->key == InputKeyOk) { | ||
furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_LEFT); | ||
furi_delay_ms(50); | ||
furi_hal_bt_hid_mouse_release(HID_MOUSE_BTN_LEFT); | ||
furi_delay_ms(50); | ||
furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_LEFT); | ||
furi_delay_ms(50); | ||
furi_hal_bt_hid_mouse_release(HID_MOUSE_BTN_LEFT); | ||
consumed = true; | ||
} else if(event->key == InputKeyUp) { | ||
// Emulate up swipe | ||
furi_hal_bt_hid_mouse_scroll(-6); | ||
furi_hal_bt_hid_mouse_scroll(-12); | ||
furi_hal_bt_hid_mouse_scroll(-19); | ||
furi_hal_bt_hid_mouse_scroll(-12); | ||
furi_hal_bt_hid_mouse_scroll(-6); | ||
consumed = true; | ||
} else if(event->key == InputKeyDown) { | ||
// Emulate down swipe | ||
furi_hal_bt_hid_mouse_scroll(6); | ||
furi_hal_bt_hid_mouse_scroll(12); | ||
furi_hal_bt_hid_mouse_scroll(19); | ||
furi_hal_bt_hid_mouse_scroll(12); | ||
furi_hal_bt_hid_mouse_scroll(6); | ||
consumed = true; | ||
} else if(event->key == InputKeyBack) { | ||
furi_hal_bt_hid_consumer_key_release_all(); | ||
consumed = true; | ||
} | ||
} | ||
|
||
return consumed; | ||
} | ||
|
||
BtHidTikTok* bt_hid_tiktok_alloc() { | ||
BtHidTikTok* bt_hid_tiktok = malloc(sizeof(BtHidTikTok)); | ||
bt_hid_tiktok->view = view_alloc(); | ||
view_set_context(bt_hid_tiktok->view, bt_hid_tiktok); | ||
view_allocate_model(bt_hid_tiktok->view, ViewModelTypeLocking, sizeof(BtHidTikTokModel)); | ||
view_set_draw_callback(bt_hid_tiktok->view, bt_hid_tiktok_draw_callback); | ||
view_set_input_callback(bt_hid_tiktok->view, bt_hid_tiktok_input_callback); | ||
|
||
return bt_hid_tiktok; | ||
} | ||
|
||
void bt_hid_tiktok_free(BtHidTikTok* bt_hid_tiktok) { | ||
furi_assert(bt_hid_tiktok); | ||
view_free(bt_hid_tiktok->view); | ||
free(bt_hid_tiktok); | ||
} | ||
|
||
View* bt_hid_tiktok_get_view(BtHidTikTok* bt_hid_tiktok) { | ||
furi_assert(bt_hid_tiktok); | ||
return bt_hid_tiktok->view; | ||
} | ||
|
||
void bt_hid_tiktok_set_connected_status(BtHidTikTok* bt_hid_tiktok, bool connected) { | ||
furi_assert(bt_hid_tiktok); | ||
with_view_model( | ||
bt_hid_tiktok->view, BtHidTikTokModel * model, { model->connected = connected; }, true); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#pragma once | ||
|
||
#include <gui/view.h> | ||
|
||
typedef struct BtHidTikTok BtHidTikTok; | ||
|
||
BtHidTikTok* bt_hid_tiktok_alloc(); | ||
|
||
void bt_hid_tiktok_free(BtHidTikTok* bt_hid_tiktok); | ||
|
||
View* bt_hid_tiktok_get_view(BtHidTikTok* bt_hid_tiktok); | ||
|
||
void bt_hid_tiktok_set_connected_status(BtHidTikTok* bt_hid_tiktok, bool connected); |