Initial check-in for hid_cookie
BIN
hid/hid_cookie/.flipcorg/banner.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
hid/hid_cookie/.flipcorg/gallery/bt-clicking.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
hid/hid_cookie/.flipcorg/gallery/credits.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
hid/hid_cookie/.flipcorg/gallery/instructions-2.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
hid/hid_cookie/.flipcorg/gallery/instructions-3.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
hid/hid_cookie/.flipcorg/gallery/main-menu.png
Normal file
After Width: | Height: | Size: 11 KiB |
11
hid/hid_cookie/application.fam
Normal file
@ -0,0 +1,11 @@
|
||||
App(
|
||||
appid="CookieBT",
|
||||
name="Cookie Clicker",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="hid_cookie_ble_app",
|
||||
stack_size=1 * 1024,
|
||||
fap_category="Tools",
|
||||
fap_icon="hid_cookie_ble_10px.png",
|
||||
fap_icon_assets="assets",
|
||||
fap_icon_assets_symbol="hid",
|
||||
)
|
BIN
hid/hid_cookie/assets/Arr_dwn_7x9.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
hid/hid_cookie/assets/Arr_up_7x9.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
hid/hid_cookie/assets/Ble_connected_15x15.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
hid/hid_cookie/assets/Ble_disconnected_15x15.png
Normal file
After Width: | Height: | Size: 657 B |
BIN
hid/hid_cookie/assets/Circles_47x47.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
hid/hid_cookie/assets/Cookie_def_11x9.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
hid/hid_cookie/assets/Cookie_pressed_17x17.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
hid/hid_cookie/assets/Pin_back_arrow_10x8.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
hid/hid_cookie/assets/Pressed_Button_13x13.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
243
hid/hid_cookie/hid.c
Normal file
@ -0,0 +1,243 @@
|
||||
#include "hid.h"
|
||||
#include "views.h"
|
||||
#include <notification/notification_messages.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#define TAG "CookieClickerApp"
|
||||
|
||||
enum HidDebugSubmenuIndex {
|
||||
HidSubmenuIndexInstructions,
|
||||
HidSubmenuIndexClicker,
|
||||
HidSubmenuIndexCredits,
|
||||
};
|
||||
|
||||
static void hid_submenu_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
Hid* app = context;
|
||||
if(index == HidSubmenuIndexInstructions) {
|
||||
app->view_id = BtHidViewInstructions;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id);
|
||||
} else if(index == HidSubmenuIndexClicker) {
|
||||
app->view_id = BtHidViewClicker;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id);
|
||||
} else if(index == HidSubmenuIndexCredits) {
|
||||
app->view_id = BtHidViewCredits;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_hid_connection_status_changed_callback(BtStatus status, void* context) {
|
||||
furi_assert(context);
|
||||
Hid* hid = context;
|
||||
bool connected = (status == BtStatusConnected);
|
||||
if(connected) {
|
||||
notification_internal_message(hid->notifications, &sequence_set_blue_255);
|
||||
} else {
|
||||
notification_internal_message(hid->notifications, &sequence_reset_blue);
|
||||
}
|
||||
hid_cc_set_connected_status(hid->hid_cc, connected);
|
||||
}
|
||||
|
||||
static uint32_t hid_submenu_view(void* context) {
|
||||
UNUSED(context);
|
||||
return HidViewSubmenu;
|
||||
}
|
||||
|
||||
static uint32_t hid_exit(void* context) {
|
||||
UNUSED(context);
|
||||
return VIEW_NONE;
|
||||
}
|
||||
|
||||
Hid* hid_alloc() {
|
||||
Hid* app = malloc(sizeof(Hid));
|
||||
|
||||
// Gui
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
// Bt
|
||||
app->bt = furi_record_open(RECORD_BT);
|
||||
|
||||
// Notifications
|
||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
// View dispatcher
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
// Submenu view
|
||||
app->submenu = submenu_alloc();
|
||||
submenu_set_header(app->submenu, "Cookie clicker");
|
||||
submenu_add_item(
|
||||
app->submenu, "Instructions", HidSubmenuIndexInstructions, hid_submenu_callback, app);
|
||||
submenu_add_item(
|
||||
app->submenu, "BT Phone Clicker", HidSubmenuIndexClicker, hid_submenu_callback, app);
|
||||
submenu_add_item(app->submenu, "Credits", HidSubmenuIndexCredits, hid_submenu_callback, app);
|
||||
view_set_previous_callback(submenu_get_view(app->submenu), hid_exit);
|
||||
view_dispatcher_add_view(app->view_dispatcher, HidViewSubmenu, submenu_get_view(app->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;
|
||||
|
||||
// Instructions view
|
||||
app->widget_instructions = widget_alloc();
|
||||
widget_add_text_scroll_element(
|
||||
app->widget_instructions,
|
||||
0,
|
||||
0,
|
||||
128,
|
||||
64,
|
||||
"While this app is running, go to\n"
|
||||
"your phone's bluetooth\n"
|
||||
"settings and discover devices.\n"
|
||||
"You should see 'Control\n"
|
||||
"<flipper>' in the list. Click pair\n"
|
||||
"on your phone. On the Flipper\n"
|
||||
"Zero you should see a pin #.\n"
|
||||
"If the pin matches, click OK on\n"
|
||||
"your phone and the Flipper.\n"
|
||||
"You should now be connected!\n"
|
||||
"Launch the Cookie clicker app\n"
|
||||
"on your phone. Tap your\n"
|
||||
"phone's screen to click on the\n"
|
||||
"first cookie, then on the\n"
|
||||
"Flipper Zero, choose\n"
|
||||
"'Phone clicker'. Click the\n"
|
||||
"UP/DOWN buttons to set the\n"
|
||||
"speed. Click the OK button on\n"
|
||||
"the Flipper to enable/\n"
|
||||
"disable the clicker.\n"
|
||||
"Enjoy!\n");
|
||||
view_set_previous_callback(widget_get_view(app->widget_instructions), hid_submenu_view);
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BtHidViewInstructions, widget_get_view(app->widget_instructions));
|
||||
|
||||
// Clicker view
|
||||
app->hid_cc = hid_cc_alloc(app);
|
||||
view_set_previous_callback(hid_cc_get_view(app->hid_cc), hid_submenu_view);
|
||||
view_dispatcher_add_view(app->view_dispatcher, BtHidViewClicker, hid_cc_get_view(app->hid_cc));
|
||||
|
||||
// Credits view
|
||||
app->widget_credits = widget_alloc();
|
||||
widget_add_text_scroll_element(
|
||||
app->widget_credits,
|
||||
0,
|
||||
0,
|
||||
128,
|
||||
64,
|
||||
"Original app was from\n"
|
||||
"external/hid_app. \n\n"
|
||||
"Modified by CodeAllNight.\n"
|
||||
"https://youtube.com/\n"
|
||||
"@MrDerekJamison\n\n"
|
||||
"Thanks to all the\n"
|
||||
"contributors of the original\n"
|
||||
"app!\n\n"
|
||||
"Flip the World!\n");
|
||||
view_set_previous_callback(widget_get_view(app->widget_credits), hid_submenu_view);
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BtHidViewCredits, widget_get_view(app->widget_credits));
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void hid_free(Hid* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// Reset notification
|
||||
notification_internal_message(app->notifications, &sequence_reset_blue);
|
||||
|
||||
// Free views
|
||||
view_dispatcher_remove_view(app->view_dispatcher, HidViewSubmenu);
|
||||
submenu_free(app->submenu);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BtHidViewClicker);
|
||||
hid_cc_free(app->hid_cc);
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
|
||||
// Close records
|
||||
furi_record_close(RECORD_GUI);
|
||||
app->gui = NULL;
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
app->notifications = NULL;
|
||||
furi_record_close(RECORD_BT);
|
||||
app->bt = NULL;
|
||||
|
||||
// Free rest
|
||||
free(app);
|
||||
}
|
||||
|
||||
void hid_hal_mouse_move(Hid* instance, int8_t dx, int8_t dy) {
|
||||
furi_assert(instance);
|
||||
furi_hal_bt_hid_mouse_move(dx, dy);
|
||||
}
|
||||
|
||||
void hid_hal_mouse_press(Hid* instance, uint16_t event) {
|
||||
furi_assert(instance);
|
||||
furi_hal_bt_hid_mouse_press(event);
|
||||
}
|
||||
|
||||
void hid_hal_mouse_release(Hid* instance, uint16_t event) {
|
||||
furi_assert(instance);
|
||||
furi_hal_bt_hid_mouse_release(event);
|
||||
}
|
||||
|
||||
void hid_hal_mouse_release_all(Hid* instance) {
|
||||
furi_assert(instance);
|
||||
furi_hal_bt_hid_mouse_release_all();
|
||||
}
|
||||
|
||||
int32_t hid_cookie_ble_app(void* p) {
|
||||
UNUSED(p);
|
||||
Hid* app = hid_alloc();
|
||||
app = hid_app_alloc_view(app);
|
||||
|
||||
bt_disconnect(app->bt);
|
||||
|
||||
// Wait 2nd core to update nvm storage
|
||||
furi_delay_ms(200);
|
||||
|
||||
// Migrate data from old sd-card folder
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
storage_common_migrate(
|
||||
storage,
|
||||
EXT_PATH("apps/Tools/" HID_BT_KEYS_STORAGE_NAME),
|
||||
APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
|
||||
|
||||
bt_keys_storage_set_storage_path(app->bt, APP_DATA_PATH(HID_BT_KEYS_STORAGE_NAME));
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
if(!bt_set_profile(app->bt, BtProfileHidKeyboard)) {
|
||||
FURI_LOG_E(TAG, "Failed to switch to HID profile");
|
||||
}
|
||||
|
||||
furi_hal_bt_start_advertising();
|
||||
bt_set_status_changed_callback(app->bt, bt_hid_connection_status_changed_callback, app);
|
||||
|
||||
DOLPHIN_DEED(DolphinDeedPluginStart);
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
|
||||
bt_set_status_changed_callback(app->bt, NULL, NULL);
|
||||
|
||||
bt_disconnect(app->bt);
|
||||
|
||||
// Wait 2nd core to update nvm storage
|
||||
furi_delay_ms(200);
|
||||
|
||||
bt_keys_storage_set_default_path(app->bt);
|
||||
|
||||
if(!bt_set_profile(app->bt, BtProfileSerial)) {
|
||||
FURI_LOG_E(TAG, "Failed to switch to Serial profile");
|
||||
}
|
||||
|
||||
hid_free(app);
|
||||
|
||||
return 0;
|
||||
}
|
41
hid/hid_cookie/hid.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal_bt.h>
|
||||
#include <furi_hal_bt_hid.h>
|
||||
#include <furi_hal_usb.h>
|
||||
#include <furi_hal_usb_hid.h>
|
||||
|
||||
#include <bt/bt_service/bt.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <notification/notification.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include "views/hid_cc.h"
|
||||
|
||||
#define HID_BT_KEYS_STORAGE_NAME ".bt_hid.keys"
|
||||
|
||||
typedef struct Hid Hid;
|
||||
|
||||
struct Hid {
|
||||
Bt* bt;
|
||||
Gui* gui;
|
||||
NotificationApp* notifications;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
Submenu* submenu;
|
||||
Widget* widget_instructions;
|
||||
Widget* widget_credits;
|
||||
HidCC* hid_cc;
|
||||
uint32_t view_id;
|
||||
};
|
||||
|
||||
void hid_hal_mouse_move(Hid* instance, int8_t dx, int8_t dy);
|
||||
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);
|
BIN
hid/hid_cookie/hid_cookie_ble_10px.png
Normal file
After Width: | Height: | Size: 151 B |
41
hid/hid_cookie/readme.md
Normal file
@ -0,0 +1,41 @@
|
||||
# Bluetooth Cookie Clicker
|
||||
The goal of this application is use the Flipper Zero's bluetooth connectivity to send mouse clicks to your phone at a given frequency. If you are playing a game, such as Cookie Clicker 2, this will result in a 'screen tap' being simulated. Only connect to phones you own (unless your friends ask you to connect your Flipper Zero to their phone, so they can unlock more achievements in their games!)
|
||||
|
||||
## Easy Setup
|
||||
The easiest way is to use [FlipC.org](https://flipc.org/build) to build the project and install on your Flipper. If the application isn't already in the [Tools](https://flipc.org/category/tools) section; you can go to [Build](https://flipc.org/build) and build it yourself.
|
||||
|
||||
```
|
||||
git: jamisonderek/flipper-zero-tutorials
|
||||
settings:
|
||||
root: /hid/hid_cookie
|
||||
```
|
||||
Then click on "Let's FAP!"
|
||||
|
||||
Once it is built, you will be able to choose to Download the FAP or install directly on your Flipper Zero!
|
||||
|
||||
## Local Setup (Windows)
|
||||
Setup your development machine with the following. You can watch my video at [YouTube](https://www.youtube.com/watch?v=gqovwRkn2xw)
|
||||
- VSCode
|
||||
- Git
|
||||
- Recursive Clone of the Flipper Zero firmware
|
||||
- Clone of this tutorial project : https://github.com/jamisonderek/flipper-zero-tutorials
|
||||
|
||||
|
||||
Once everything is cloned, copy the hid_cookie project into your applications_user folder...
|
||||
- Open the firmware project in Visual Studio Code
|
||||
- Right click on "applications_user"
|
||||
- Choose "Open in Integrated Terminal"
|
||||
- Type:
|
||||
```
|
||||
New-Item -Path hid_cookie -ItemType Junction -Value ..\..\flipper-zero-tutorials\hid\hid_cookie
|
||||
```
|
||||
|
||||
Once everything is copied, build and run the project...
|
||||
- Open the build task window (Ctrl+Shift+B)
|
||||
- Choose "Build update bundle"
|
||||
- Open the "applications_user\hid_cookie\hid.c" file
|
||||
- Open the build task window (Ctrl+Shift+B)
|
||||
- Choose "Launch app on Flipper"
|
||||
|
||||
## Using the app
|
||||
Once the application is launched, it will show a menu that includes directions for using the application. Press the OK button to launch the instructions. Press the DOWN button to read more instructions. Press the BACK button to return to the menu.
|
7
hid/hid_cookie/views.h
Normal file
@ -0,0 +1,7 @@
|
||||
typedef enum {
|
||||
HidViewSubmenu,
|
||||
BtHidViewInstructions,
|
||||
BtHidViewClicker,
|
||||
BtHidViewCredits,
|
||||
HidViewExitConfirm,
|
||||
} HidView;
|
241
hid/hid_cookie/views/hid_cc.c
Normal file
@ -0,0 +1,241 @@
|
||||
#include "hid_cc.h"
|
||||
#include "../hid.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
#include "hid_icons.h"
|
||||
|
||||
#define TAG "HidCC"
|
||||
|
||||
struct HidCC {
|
||||
View* view;
|
||||
Hid* hid;
|
||||
FuriTimer* timer;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bool left_pressed;
|
||||
bool up_pressed;
|
||||
bool right_pressed;
|
||||
bool down_pressed;
|
||||
bool ok_pressed;
|
||||
bool connected;
|
||||
bool is_cursor_set;
|
||||
float timer_duration;
|
||||
bool timer_click_enabled;
|
||||
} HidCCModel;
|
||||
|
||||
static void hid_cc_draw_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
HidCCModel* 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, "Cookie\nClicker");
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
FuriString* buffer = furi_string_alloc(32);
|
||||
furi_string_printf(buffer, "%0.1f ms\r\n", (double)model->timer_duration);
|
||||
if(model->timer_click_enabled) {
|
||||
furi_string_cat(buffer, "Clicking");
|
||||
}
|
||||
elements_multiline_text_aligned(
|
||||
canvas, 17, 25, AlignLeft, AlignTop, furi_string_get_cstr(buffer));
|
||||
furi_string_free(buffer);
|
||||
|
||||
// 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);
|
||||
|
||||
// Ok
|
||||
if(model->ok_pressed) {
|
||||
canvas_draw_icon(canvas, 91, 23, &I_Cookie_pressed_17x17);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, 94, 27, &I_Cookie_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, "Back to menu");
|
||||
}
|
||||
|
||||
static void hid_cc_update_timer(HidCC* hid_cc, HidCCModel* model) {
|
||||
furi_assert(hid_cc);
|
||||
furi_assert(model);
|
||||
if(model->timer_click_enabled) {
|
||||
furi_timer_start(hid_cc->timer, model->timer_duration);
|
||||
} else {
|
||||
furi_timer_stop(hid_cc->timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_cc_tick_callback(void* context) {
|
||||
furi_assert(context);
|
||||
HidCC* hid_cc = context;
|
||||
|
||||
with_view_model(
|
||||
hid_cc->view,
|
||||
HidCCModel * model,
|
||||
{
|
||||
if(model->timer_click_enabled) {
|
||||
hid_hal_mouse_press(hid_cc->hid, HID_MOUSE_BTN_LEFT);
|
||||
furi_delay_ms(10);
|
||||
hid_hal_mouse_release(hid_cc->hid, HID_MOUSE_BTN_LEFT);
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
static void hid_cc_reset_cursor(HidCC* hid_cc) {
|
||||
// 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_cc->hid, -127, -127);
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
// Move cursor from the corner
|
||||
hid_hal_mouse_move(hid_cc->hid, 20, 120);
|
||||
furi_delay_ms(50);
|
||||
}
|
||||
|
||||
static void hid_cc_process_press(HidCC* hid_cc, HidCCModel* model, InputEvent* event) {
|
||||
if(event->key == InputKeyUp) {
|
||||
model->up_pressed = true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
model->down_pressed = true;
|
||||
} else if(event->key == InputKeyOk) {
|
||||
model->ok_pressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_cc_process_release(HidCC* hid_cc, HidCCModel* model, InputEvent* event) {
|
||||
if(event->key == InputKeyUp) {
|
||||
model->up_pressed = false;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
model->down_pressed = false;
|
||||
} else if(event->key == InputKeyOk) {
|
||||
model->ok_pressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool hid_cc_input_callback(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
HidCC* hid_cc = context;
|
||||
bool consumed = false;
|
||||
|
||||
with_view_model(
|
||||
hid_cc->view,
|
||||
HidCCModel * model,
|
||||
{
|
||||
if(event->type == InputTypePress) {
|
||||
hid_cc_process_press(hid_cc, model, event);
|
||||
if(model->connected && !model->is_cursor_set) {
|
||||
hid_cc_reset_cursor(hid_cc);
|
||||
model->is_cursor_set = true;
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
hid_cc_process_release(hid_cc, model, event);
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyOk) {
|
||||
model->timer_click_enabled = !model->timer_click_enabled;
|
||||
hid_cc_update_timer(hid_cc, model);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
// Reduce duration to 95% of value + update_timer.
|
||||
if(model->timer_duration > 0) {
|
||||
model->timer_duration *= 0.95f;
|
||||
hid_cc_update_timer(hid_cc, model);
|
||||
}
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
// Increase duration to 105% of value + update_timer
|
||||
model->timer_duration *= 1.05f;
|
||||
hid_cc_update_timer(hid_cc, model);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyBack) {
|
||||
hid_hal_mouse_release_all(hid_cc->hid);
|
||||
model->is_cursor_set = false;
|
||||
consumed = false;
|
||||
}
|
||||
} else if(event->type == InputTypeLong) {
|
||||
if(event->key == InputKeyBack) {
|
||||
hid_hal_mouse_release_all(hid_cc->hid);
|
||||
model->is_cursor_set = false;
|
||||
consumed = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
true);
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
HidCC* hid_cc_alloc(Hid* bt_hid) {
|
||||
HidCC* hid_cc = malloc(sizeof(HidCC));
|
||||
hid_cc->hid = bt_hid;
|
||||
hid_cc->view = view_alloc();
|
||||
view_set_context(hid_cc->view, hid_cc);
|
||||
view_allocate_model(hid_cc->view, ViewModelTypeLocking, sizeof(HidCCModel));
|
||||
view_set_draw_callback(hid_cc->view, hid_cc_draw_callback);
|
||||
view_set_input_callback(hid_cc->view, hid_cc_input_callback);
|
||||
|
||||
with_view_model(
|
||||
hid_cc->view,
|
||||
HidCCModel * model,
|
||||
{
|
||||
model->timer_duration = 22.0f;
|
||||
model->timer_click_enabled = false;
|
||||
},
|
||||
true);
|
||||
hid_cc->timer = furi_timer_alloc(hid_cc_tick_callback, FuriTimerTypePeriodic, hid_cc);
|
||||
return hid_cc;
|
||||
}
|
||||
|
||||
void hid_cc_free(HidCC* hid_cc) {
|
||||
furi_assert(hid_cc);
|
||||
furi_timer_free(hid_cc->timer);
|
||||
view_free(hid_cc->view);
|
||||
free(hid_cc);
|
||||
}
|
||||
|
||||
View* hid_cc_get_view(HidCC* hid_cc) {
|
||||
furi_assert(hid_cc);
|
||||
return hid_cc->view;
|
||||
}
|
||||
|
||||
void hid_cc_set_connected_status(HidCC* hid_cc, bool connected) {
|
||||
furi_assert(hid_cc);
|
||||
with_view_model(
|
||||
hid_cc->view,
|
||||
HidCCModel * model,
|
||||
{
|
||||
model->connected = connected;
|
||||
model->is_cursor_set = false;
|
||||
},
|
||||
true);
|
||||
}
|
14
hid/hid_cookie/views/hid_cc.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct Hid Hid;
|
||||
typedef struct HidCC HidCC;
|
||||
|
||||
HidCC* hid_cc_alloc(Hid* bt_hid);
|
||||
|
||||
void hid_cc_free(HidCC* hid_cc);
|
||||
|
||||
View* hid_cc_get_view(HidCC* hid_cc);
|
||||
|
||||
void hid_cc_set_connected_status(HidCC* hid_cc, bool connected);
|