diff --git a/.drone.yml b/.drone.yml index 1bdcef0c0..f0582c207 100644 --- a/.drone.yml +++ b/.drone.yml @@ -85,7 +85,7 @@ steps: Version: {{build.tag}} - [-Github-](https://github.com/Eng1n33r/flipperzero-firmware/releases/tag/${DRONE_TAG}) + [-Github-](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/${DRONE_TAG}) [-Install via Web Updater-](https://my.flipp.dev/?url=https://unleashedflip.com/builds/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})" @@ -105,7 +105,7 @@ steps: Version: {{build.tag}} - [[Github]](https://github.com/Eng1n33r/flipperzero-firmware/releases/tag/${DRONE_TAG}) + [[Github]](https://github.com/DarkFlippers/unleashed-firmware/releases/tag/${DRONE_TAG}) [-Install via Web Updater-](https://my.flipp.dev/?url=https://unleashedflip.com/builds/flipper-z-f7-update-${DRONE_TAG}.tgz&channel=dev-cfw&version=${DRONE_TAG})" diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c7750c5e..a733052fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,43 @@ ### New changes -* Add 312.2 MHz to subghz user config -* PR: Add CAME 12bit 303MHz to SubGHz Bruteforcer (by @derskythe | PR #87) -* PR: Added norwegian keyboard layout for badusb (by @jd-raymaker | PR #88) -* Adapted all plugins and other code to new FuriString, fixed archive menu issues with new string type -* SubGHz: Fix double click after delete scene, fix rename bug +* Issues with hopping in subghz are fixed in this release +* OFW PR: Desktop: Set external apps as favorites (OFW PR 1816 by @djsime1) (and fixed forgotten furi_record_close) +* PR -> Plugins: Add CAME 12bit 303MHz to SubGHz Bruteforcer (by @derskythe | PR #87) +* PR -> BadUSB: Added Norwegian keyboard layout for BadUSB (by @jd-raymaker | PR #88) +* PR -> Plugins: Feature: allow to set ball speed in Arkanoid (by @an4tur0r | PR #92) +* Add USB Keyboard (& Mouse) plugin, replacing default USB Mouse demo included (plugin by @huuck) [Link to original](https://github.com/huuck/FlipperZeroUSBKeyboard) +* Fix USB Keyboard plugin wrong icon in mouse screen, rewrite view models to new type +* Updated universal remote assets (by @Amec0e) * Plugins: SubGHz Bruteforcer - Fix wrong max value in BF existing dump -* API 3.0 -> 3.1 (all previous compiled apps still compatible) +* API 3.0 -> 3.2 (all previous compiled apps still compatible) +* Add 312.2 MHz to subghz user config +* SubGHz: Fix double click after delete scene, fix rename bug * SubGHz: proper free of rainbow tables +* SubGHz: Fixed stability issues with Came atomo, Nice Flor S, limited max history items to 60 (was 65) +* SubGHz: Fix Read screen GUI (still bugged in OFW) +* Adapted all plugins and other code to new FuriString, fixed all new issues with new string type +* Adapted all plugins to new printf format +* Adapted all plugins to new view model format (aka Removing lambdas) +* Adapted all plugins to new furi_stream +* OFW: Elf loader: do not load .ARM.* sections +* OFW: Removing lambdas +* OFW: BadUSB: add SYSRQ keys +* OFW: Gui: fix memory leak in file browser module +* OFW: music_player: Return to browser instead of exiting on back button +* OFW: More correct elf loader +* OFW: Furi stream buffer +* OFW: Printf function attributes +* OFW: App name in CLI loader command, RFID data edit fix * OFW: Show in-app icons & names in archive browser * OFW: M*LIB: non-inlined strings, FuriString primitive -* OFW PR: Remove string_push_uint64 (OFW PR 1832 by Astrrra) +* OFW: Remove string_push_uint64 +* OFW: Mifare Classic read improvements * OFW PR: updated icon names (OFW PR 1829 by nminaylov) #### [🎲 Download extra apps pack](https://download-directory.github.io/?url=https://github.com/UberGuidoZ/Flipper/tree/main/Applications/Unleashed) -[-> How to install firmware](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md) +[-> How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md) -[-> Download qFlipper 1.2.0 (allows .tgz installation) (official link)](https://update.flipperzero.one/builds/qFlipper/1.2.0/) +[-> Download qFlipper 1.2.1 (allows .tgz installation) (official link)](https://update.flipperzero.one/builds/qFlipper/1.2.1/) ## Please support development of the project * ETH/BSC/ERC20-Tokens: `0xFebF1bBc8229418FF2408C07AF6Afa49152fEc6a` @@ -28,5 +49,5 @@ Self-update package (update from microSD) - `flipper-z-f7-update-(version).zip` or download `.tgz` for iOS mobile app / qFlipper -Update using qFlipper (1.2.0) is now possible with `.tgz` update package! Also you can use Web Updater or self-update package. +Update using qFlipper (1.2.0+) is now possible with `.tgz` update package! Also you can use Web Updater or self-update package. diff --git a/ReadMe.md b/ReadMe.md index ca765145b..d30c86dd3 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,5 +1,5 @@

- + fzCUSTOM

@@ -62,12 +62,13 @@ Also check changelog in releases for latest updates! ### Community apps included: -- RFID Fuzzer plugin [(by Ganapati)](https://github.com/Eng1n33r/flipperzero-firmware/pull/54) with changes by @xMasterX & New protocols by @mvanzanten -- Sub-GHz bruteforce plugin [(by Ganapati & xMasterX)](https://github.com/Eng1n33r/flipperzero-firmware/pull/57) & Refactored by @derskythe -- Sub-GHz playlist plugin [(by darmiel)](https://github.com/Eng1n33r/flipperzero-firmware/pull/62) +- RFID Fuzzer plugin [(by Ganapati)](https://github.com/DarkFlippers/unleashed-firmware/pull/54) with changes by @xMasterX & New protocols by @mvanzanten +- Sub-GHz bruteforce plugin [(by Ganapati & xMasterX)](https://github.com/DarkFlippers/unleashed-firmware/pull/57) & Refactored by @derskythe +- Sub-GHz playlist plugin [(by darmiel)](https://github.com/DarkFlippers/unleashed-firmware/pull/62) - ESP8266 Deauther plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-Wifi-ESP8266-Deauther-Module) - WiFi Scanner plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module) - MultiConverter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff) +- USB Keyboard plugin [(by huuck)](https://github.com/huuck/FlipperZeroUSBKeyboard) - WAV player plugin (fixed) [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player) - UPC-A Barcode generator plugin [(by McAzzaMan)](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator) - GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin) @@ -88,30 +89,30 @@ Games: ### Other changes - BadUSB -> Keyboard layouts [(by rien > dummy-decoy)](https://github.com/dummy-decoy/flipperzero-firmware/tree/dummy_decoy/bad_usb_keyboard_layout) -- SubGHz -> New frequency analyzer - [(by ClusterM)](https://github.com/Eng1n33r/flipperzero-firmware/pull/43) +- SubGHz -> New frequency analyzer - [(by ClusterM)](https://github.com/DarkFlippers/unleashed-firmware/pull/43) - SubGHz -> Detect RAW feature - [(by perspecdev)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/152) -- SubGHz -> Save last used frequency and moduluation [(by derskythe)](https://github.com/Eng1n33r/flipperzero-firmware/pull/77) -- SubGHz -> Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/Eng1n33r/flipperzero-firmware/pull/77) -* SubGHz -> Long press OK button in SubGHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/Eng1n33r/flipperzero-firmware/pull/79) +- SubGHz -> Save last used frequency and moduluation [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77) +- SubGHz -> Press OK in frequency analyzer to use detected frequency in Read modes [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/77) +* SubGHz -> Long press OK button in SubGHz Frequency analyzer to switch to Read menu [(by derskythe)](https://github.com/DarkFlippers/unleashed-firmware/pull/79) # Instructions -## [- How to install firmware](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md) +## [- How to install firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md) -## [- How to build firmware](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToBuild.md) +## [- How to build firmware](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToBuild.md) ## [- BadUSB: how to add new keyboard layouts](https://github.com/dummy-decoy/flipperzero_badusb_kl) -## [- How to change Flipper name](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/CustomFlipperName.md) +## [- How to change Flipper name](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/CustomFlipperName.md) ### **Plugins** ## [- 🎲 Download Extra plugins for Unleashed](https://github.com/UberGuidoZ/Flipper/tree/main/Applications/Unleashed) -## [- Configure Sub-GHz Remote App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SubGHzRemotePlugin.md) +## [- Configure Sub-GHz Remote App](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md) -## [- Barcode Generator](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/BarcodeGenerator.md) +## [- Barcode Generator](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/BarcodeGenerator.md) -## [- Multi Converter](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/MultiConverter.md) +## [- Multi Converter](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/MultiConverter.md) ## [- WAV Player sample files & how to convert](https://github.com/UberGuidoZ/Flipper/tree/main/Wav_Player#readme) @@ -119,7 +120,7 @@ Games: ### **Plugins that works with external hardware** -## [- How to use: [NRF24] plugins](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/NRF24.md) +## [- How to use: [NRF24] plugins](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/NRF24.md) ## [- How to use: [WiFi] Scanner](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module#readme) @@ -133,13 +134,13 @@ Games: ## [- Windows: How to Upload .bin to ESP32/ESP8266](https://github.com/SequoiaSan/Guide-How-To-Upload-bin-to-ESP8266-ESP32) -## [- How to use: [GPIO] SentrySafe plugin](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SentrySafe.md) +## [- How to use: [GPIO] SentrySafe plugin](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SentrySafe.md) ### **SubGHz** -## [- Transmission is blocked? - How to extend SubGHz frequency range](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/DangerousSettings.md) +## [- Transmission is blocked? - How to extend SubGHz frequency range](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/DangerousSettings.md) -## [- How to add extra SubGHz frequencies](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SubGHzSettings.md) +## [- How to add extra SubGHz frequencies](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzSettings.md)

diff --git a/applications/debug/bt_debug_app/views/bt_test.c b/applications/debug/bt_debug_app/views/bt_test.c index 9f2830d34..9588b667b 100644 --- a/applications/debug/bt_debug_app/views/bt_test.c +++ b/applications/debug/bt_debug_app/views/bt_test.c @@ -154,7 +154,9 @@ static bool bt_test_input_callback(InputEvent* event, void* context) { void bt_test_process_up(BtTest* bt_test) { with_view_model( - bt_test->view, (BtTestModel * model) { + bt_test->view, + BtTestModel * model, + { uint8_t params_on_screen = 3; if(model->position > 0) { model->position--; @@ -168,13 +170,15 @@ void bt_test_process_up(BtTest* bt_test) { model->window_position = model->position - (params_on_screen - 1); } } - return true; - }); + }, + true); } void bt_test_process_down(BtTest* bt_test) { with_view_model( - bt_test->view, (BtTestModel * model) { + bt_test->view, + BtTestModel * model, + { uint8_t params_on_screen = 3; if(model->position < (BtTestParamArray_size(model->params) - 1)) { model->position++; @@ -187,8 +191,8 @@ void bt_test_process_down(BtTest* bt_test) { model->position = 0; model->window_position = 0; } - return true; - }); + }, + true); } BtTestParam* bt_test_get_selected_param(BtTestModel* model) { @@ -213,7 +217,9 @@ BtTestParam* bt_test_get_selected_param(BtTestModel* model) { void bt_test_process_left(BtTest* bt_test) { BtTestParam* param; with_view_model( - bt_test->view, (BtTestModel * model) { + bt_test->view, + BtTestModel * model, + { param = bt_test_get_selected_param(model); if(param->current_value_index > 0) { param->current_value_index--; @@ -225,8 +231,8 @@ void bt_test_process_left(BtTest* bt_test) { model->packets_num_tx = 0; } } - return true; - }); + }, + true); if(param->change_callback) { param->change_callback(param); } @@ -235,7 +241,9 @@ void bt_test_process_left(BtTest* bt_test) { void bt_test_process_right(BtTest* bt_test) { BtTestParam* param; with_view_model( - bt_test->view, (BtTestModel * model) { + bt_test->view, + BtTestModel * model, + { param = bt_test_get_selected_param(model); if(param->current_value_index < (param->values_count - 1)) { param->current_value_index++; @@ -247,8 +255,8 @@ void bt_test_process_right(BtTest* bt_test) { model->packets_num_tx = 0; } } - return true; - }); + }, + true); if(param->change_callback) { param->change_callback(param); } @@ -257,7 +265,9 @@ void bt_test_process_right(BtTest* bt_test) { void bt_test_process_ok(BtTest* bt_test) { BtTestState state; with_view_model( - bt_test->view, (BtTestModel * model) { + bt_test->view, + BtTestModel * model, + { if(model->state == BtTestStateStarted) { model->state = BtTestStateStopped; model->message = BT_TEST_START_MESSAGE; @@ -269,8 +279,8 @@ void bt_test_process_ok(BtTest* bt_test) { model->message = BT_TEST_STOP_MESSAGE; } state = model->state; - return true; - }); + }, + true); if(bt_test->change_state_callback) { bt_test->change_state_callback(state, bt_test->context); } @@ -278,13 +288,15 @@ void bt_test_process_ok(BtTest* bt_test) { void bt_test_process_back(BtTest* bt_test) { with_view_model( - bt_test->view, (BtTestModel * model) { + bt_test->view, + BtTestModel * model, + { model->state = BtTestStateStopped; model->rssi = 0.0f; model->packets_num_rx = 0; model->packets_num_tx = 0; - return false; - }); + }, + false); if(bt_test->back_callback) { bt_test->back_callback(bt_test->context); } @@ -299,7 +311,9 @@ BtTest* bt_test_alloc() { view_set_input_callback(bt_test->view, bt_test_input_callback); with_view_model( - bt_test->view, (BtTestModel * model) { + bt_test->view, + BtTestModel * model, + { model->state = BtTestStateStopped; model->message = "Ok - Start"; BtTestParamArray_init(model->params); @@ -308,8 +322,8 @@ BtTest* bt_test_alloc() { model->rssi = 0.0f; model->packets_num_tx = 0; model->packets_num_rx = 0; - return true; - }); + }, + true); return bt_test; } @@ -318,15 +332,17 @@ void bt_test_free(BtTest* bt_test) { furi_assert(bt_test); with_view_model( - bt_test->view, (BtTestModel * model) { + bt_test->view, + BtTestModel * model, + { BtTestParamArray_it_t it; for(BtTestParamArray_it(it, model->params); !BtTestParamArray_end_p(it); BtTestParamArray_next(it)) { furi_string_free(BtTestParamArray_ref(it)->current_value_text); } BtTestParamArray_clear(model->params); - return false; - }); + }, + false); view_free(bt_test->view); free(bt_test); } @@ -347,7 +363,9 @@ BtTestParam* bt_test_param_add( furi_assert(bt_test); with_view_model( - bt_test->view, (BtTestModel * model) { + bt_test->view, + BtTestModel * model, + { param = BtTestParamArray_push_new(model->params); param->label = label; param->values_count = values_count; @@ -355,8 +373,8 @@ BtTestParam* bt_test_param_add( param->context = context; param->current_value_index = 0; param->current_value_text = furi_string_alloc(); - return true; - }); + }, + true); return param; } @@ -364,28 +382,19 @@ BtTestParam* bt_test_param_add( void bt_test_set_rssi(BtTest* bt_test, float rssi) { furi_assert(bt_test); with_view_model( - bt_test->view, (BtTestModel * model) { - model->rssi = rssi; - return true; - }); + bt_test->view, BtTestModel * model, { model->rssi = rssi; }, true); } void bt_test_set_packets_tx(BtTest* bt_test, uint32_t packets_num) { furi_assert(bt_test); with_view_model( - bt_test->view, (BtTestModel * model) { - model->packets_num_tx = packets_num; - return true; - }); + bt_test->view, BtTestModel * model, { model->packets_num_tx = packets_num; }, true); } void bt_test_set_packets_rx(BtTest* bt_test, uint32_t packets_num) { furi_assert(bt_test); with_view_model( - bt_test->view, (BtTestModel * model) { - model->packets_num_rx = packets_num; - return true; - }); + bt_test->view, BtTestModel * model, { model->packets_num_rx = packets_num; }, true); } void bt_test_set_change_state_callback(BtTest* bt_test, BtTestChangeStateCallback callback) { diff --git a/applications/debug/display_test/view_display_test.c b/applications/debug/display_test/view_display_test.c index f00fe0094..b47c74c6c 100644 --- a/applications/debug/display_test/view_display_test.c +++ b/applications/debug/display_test/view_display_test.c @@ -110,7 +110,9 @@ static bool view_display_test_input_callback(InputEvent* event, void* context) { bool consumed = false; if(event->type == InputTypeShort || event->type == InputTypeRepeat) { with_view_model( - instance->view, (ViewDisplayTestModel * model) { + instance->view, + ViewDisplayTestModel * model, + { if(event->key == InputKeyLeft && model->test > 0) { model->test--; consumed = true; @@ -129,8 +131,8 @@ static bool view_display_test_input_callback(InputEvent* event, void* context) { model->flip_flop = !model->flip_flop; consumed = true; } - return consumed; - }); + }, + consumed); } return consumed; @@ -149,10 +151,7 @@ static void view_display_test_exit(void* context) { static void view_display_test_timer_callback(void* context) { ViewDisplayTest* instance = context; with_view_model( - instance->view, (ViewDisplayTestModel * model) { - model->counter++; - return true; - }); + instance->view, ViewDisplayTestModel * model, { model->counter++; }, true); } ViewDisplayTest* view_display_test_alloc() { diff --git a/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c index 38fe36036..fd221c4e9 100644 --- a/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c +++ b/applications/debug/lfrfid_debug/views/lfrfid_debug_view_tune.c @@ -52,23 +52,29 @@ static void lfrfid_debug_view_tune_draw_callback(Canvas* canvas, void* _model) { static void lfrfid_debug_view_tune_button_up(LfRfidTuneView* tune_view) { with_view_model( - tune_view->view, (LfRfidTuneViewModel * model) { + tune_view->view, + LfRfidTuneViewModel * model, + { if(model->pos > 0) model->pos--; - return true; - }); + }, + true); } static void lfrfid_debug_view_tune_button_down(LfRfidTuneView* tune_view) { with_view_model( - tune_view->view, (LfRfidTuneViewModel * model) { + tune_view->view, + LfRfidTuneViewModel * model, + { if(model->pos < 1) model->pos++; - return true; - }); + }, + true); } static void lfrfid_debug_view_tune_button_left(LfRfidTuneView* tune_view) { with_view_model( - tune_view->view, (LfRfidTuneViewModel * model) { + tune_view->view, + LfRfidTuneViewModel * model, + { if(model->pos == 0) { if(model->fine) { model->ARR -= 1; @@ -84,13 +90,15 @@ static void lfrfid_debug_view_tune_button_left(LfRfidTuneView* tune_view) { } model->dirty = true; - return true; - }); + }, + true); } static void lfrfid_debug_view_tune_button_right(LfRfidTuneView* tune_view) { with_view_model( - tune_view->view, (LfRfidTuneViewModel * model) { + tune_view->view, + LfRfidTuneViewModel * model, + { if(model->pos == 0) { if(model->fine) { model->ARR += 1; @@ -106,16 +114,13 @@ static void lfrfid_debug_view_tune_button_right(LfRfidTuneView* tune_view) { } model->dirty = true; - return true; - }); + }, + true); } static void lfrfid_debug_view_tune_button_ok(LfRfidTuneView* tune_view) { with_view_model( - tune_view->view, (LfRfidTuneViewModel * model) { - model->fine = !model->fine; - return true; - }); + tune_view->view, LfRfidTuneViewModel * model, { model->fine = !model->fine; }, true); } static bool lfrfid_debug_view_tune_input_callback(InputEvent* event, void* context) { @@ -158,14 +163,16 @@ LfRfidTuneView* lfrfid_debug_view_tune_alloc() { view_allocate_model(tune_view->view, ViewModelTypeLocking, sizeof(LfRfidTuneViewModel)); with_view_model( - tune_view->view, (LfRfidTuneViewModel * model) { + tune_view->view, + LfRfidTuneViewModel * model, + { model->dirty = true; model->fine = false; model->ARR = 511; model->CCR = 255; model->pos = 0; - return true; - }); + }, + true); view_set_draw_callback(tune_view->view, lfrfid_debug_view_tune_draw_callback); view_set_input_callback(tune_view->view, lfrfid_debug_view_tune_input_callback); @@ -184,24 +191,28 @@ View* lfrfid_debug_view_tune_get_view(LfRfidTuneView* tune_view) { void lfrfid_debug_view_tune_clean(LfRfidTuneView* tune_view) { with_view_model( - tune_view->view, (LfRfidTuneViewModel * model) { + tune_view->view, + LfRfidTuneViewModel * model, + { model->dirty = true; model->fine = false; model->ARR = 511; model->CCR = 255; model->pos = 0; - return true; - }); + }, + true); } bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) { bool result = false; with_view_model( - tune_view->view, (LfRfidTuneViewModel * model) { + tune_view->view, + LfRfidTuneViewModel * model, + { result = model->dirty; model->dirty = false; - return false; - }); + }, + false); return result; } @@ -209,10 +220,7 @@ bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) { uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) { uint32_t result = false; with_view_model( - tune_view->view, (LfRfidTuneViewModel * model) { - result = model->ARR; - return false; - }); + tune_view->view, LfRfidTuneViewModel * model, { result = model->ARR; }, false); return result; } @@ -220,10 +228,7 @@ uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) { uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view) { uint32_t result = false; with_view_model( - tune_view->view, (LfRfidTuneViewModel * model) { - result = model->CCR; - return false; - }); + tune_view->view, LfRfidTuneViewModel * model, { result = model->CCR; }, false); return result; } diff --git a/applications/debug/uart_echo/uart_echo.c b/applications/debug/uart_echo/uart_echo.c index 122862dd9..701e5325a 100644 --- a/applications/debug/uart_echo/uart_echo.c +++ b/applications/debug/uart_echo/uart_echo.c @@ -159,21 +159,20 @@ static int32_t uart_echo_worker(void* context) { if(length > 0) { furi_hal_uart_tx(FuriHalUartIdUSART1, data, length); with_view_model( - app->view, (UartDumpModel * model) { + app->view, + UartDumpModel * model, + { for(size_t i = 0; i < length; i++) { uart_echo_push_to_list(model, data[i]); } - return false; - }); + }, + false); } } while(length > 0); notification_message(app->notification, &sequence_notification); with_view_model( - app->view, (UartDumpModel * model) { - UNUSED(model); - return true; - }); + app->view, UartDumpModel * model, { UNUSED(model); }, true); } } @@ -200,15 +199,17 @@ static UartEchoApp* uart_echo_app_alloc() { view_set_input_callback(app->view, uart_echo_view_input_callback); view_allocate_model(app->view, ViewModelTypeLocking, sizeof(UartDumpModel)); with_view_model( - app->view, (UartDumpModel * model) { + app->view, + UartDumpModel * model, + { for(size_t i = 0; i < LINES_ON_SCREEN; i++) { model->line = 0; model->escape = false; model->list[i] = malloc(sizeof(ListElement)); model->list[i]->text = furi_string_alloc(); } - return true; - }); + }, + true); view_set_previous_callback(app->view, uart_echo_exit); view_dispatcher_add_view(app->view_dispatcher, 0, app->view); @@ -242,13 +243,15 @@ static void uart_echo_app_free(UartEchoApp* app) { view_dispatcher_remove_view(app->view_dispatcher, 0); with_view_model( - app->view, (UartDumpModel * model) { + app->view, + UartDumpModel * model, + { for(size_t i = 0; i < LINES_ON_SCREEN; i++) { furi_string_free(model->list[i]->text); free(model->list[i]); } - return true; - }); + }, + true); view_free(app->view); view_dispatcher_free(app->view_dispatcher); diff --git a/applications/debug/usb_mouse/application.fam b/applications/debug/usb_mouse/application.fam index fb7595e10..bf555c671 100644 --- a/applications/debug/usb_mouse/application.fam +++ b/applications/debug/usb_mouse/application.fam @@ -1,12 +1,12 @@ App( appid="USB_Mouse", name="USB Mouse", - apptype=FlipperAppType.PLUGIN, + apptype=FlipperAppType.DEBUG, entry_point="usb_mouse_app", cdefines=["APP_USB_MOUSE"], requires=["gui"], stack_size=1 * 1024, order=60, fap_icon="../../plugins/mousejacker/mouse_10px.png", - fap_category="Misc", + fap_category="Debug", ) diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index 0f44cf585..01ba4a994 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -21,7 +21,9 @@ static void archive_switch_tab(browser, browser->last_tab_switch_dir); } else if(!furi_string_start_with_str(browser->path, "/app:")) { with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { files_array_reset(model->files); model->item_cnt = item_cnt; model->item_idx = (file_idx > 0) ? file_idx : 0; @@ -31,8 +33,8 @@ static void model->list_offset = 0; model->list_loading = true; model->folder_loading = false; - return false; - }); + }, + false); archive_update_offset(browser); file_browser_worker_load(browser->worker, load_offset, FILE_LIST_BUF_LEN); @@ -44,11 +46,13 @@ static void archive_list_load_cb(void* context, uint32_t list_load_offset) { ArchiveBrowserView* browser = (ArchiveBrowserView*)context; with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { files_array_reset(model->files); model->array_offset = list_load_offset; - return false; - }); + }, + false); } static void @@ -60,10 +64,7 @@ static void archive_add_file_item(browser, is_folder, furi_string_get_cstr(item_path)); } else { with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { - model->list_loading = false; - return true; - }); + browser->view, ArchiveBrowserViewModel * model, { model->list_loading = false; }, true); } } @@ -72,10 +73,7 @@ static void archive_long_load_cb(void* context) { ArchiveBrowserView* browser = (ArchiveBrowserView*)context; with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { - model->folder_loading = true; - return true; - }); + browser->view, ArchiveBrowserViewModel * model, { model->folder_loading = true; }, true); } static void archive_file_browser_set_path( @@ -113,7 +111,9 @@ void archive_update_offset(ArchiveBrowserView* browser) { furi_assert(browser); with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { uint16_t bounds = model->item_cnt > 3 ? 2 : model->item_cnt; if((model->item_cnt > 3u) && (model->item_idx >= ((int32_t)model->item_cnt - 1))) { @@ -125,9 +125,8 @@ void archive_update_offset(ArchiveBrowserView* browser) { model->list_offset = CLAMP(model->item_idx - 1, (int32_t)model->item_cnt - bounds, 0); } - - return true; - }); + }, + true); } void archive_update_focus(ArchiveBrowserView* browser, const char* target) { @@ -140,7 +139,9 @@ void archive_update_focus(ArchiveBrowserView* browser, const char* target) { archive_switch_tab(browser, TAB_RIGHT); } else { with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { uint16_t idx = 0; while(idx < files_array_size(model->files)) { ArchiveFile_t* current = files_array_get(model->files, idx); @@ -150,8 +151,8 @@ void archive_update_focus(ArchiveBrowserView* browser, const char* target) { } ++idx; } - return false; - }); + }, + false); archive_update_offset(browser); } @@ -162,10 +163,10 @@ size_t archive_file_get_array_size(ArchiveBrowserView* browser) { uint16_t size = 0; with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { - size = files_array_size(model->files); - return false; - }); + browser->view, + ArchiveBrowserViewModel * model, + { size = files_array_size(model->files); }, + false); return size; } @@ -173,11 +174,13 @@ void archive_set_item_count(ArchiveBrowserView* browser, uint32_t count) { furi_assert(browser); with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { model->item_cnt = count; model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0); - return false; - }); + }, + false); archive_update_offset(browser); } @@ -186,7 +189,9 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) { uint32_t items_cnt = 0; with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { files_array_remove_v( model->files, model->item_idx - model->array_offset, @@ -194,8 +199,8 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) { model->item_cnt--; model->item_idx = CLAMP(model->item_idx, (int32_t)model->item_cnt - 1, 0); items_cnt = model->item_cnt; - return false; - }); + }, + false); if((items_cnt == 0) && (archive_is_home(browser))) { archive_switch_tab(browser, TAB_RIGHT); @@ -208,7 +213,9 @@ void archive_file_array_swap(ArchiveBrowserView* browser, int8_t dir) { furi_assert(browser); with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { ArchiveFile_t temp; size_t array_size = files_array_size(model->files) - 1; uint8_t swap_idx = CLAMP((size_t)(model->item_idx + dir), array_size, 0u); @@ -226,18 +233,18 @@ void archive_file_array_swap(ArchiveBrowserView* browser, int8_t dir) { } else { files_array_swap_at(model->files, model->item_idx, swap_idx); } - return false; - }); + }, + false); } void archive_file_array_rm_all(ArchiveBrowserView* browser) { furi_assert(browser); with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { - files_array_reset(model->files); - return false; - }); + browser->view, + ArchiveBrowserViewModel * model, + { files_array_reset(model->files); }, + false); } void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) { @@ -246,7 +253,9 @@ void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) { int32_t offset_new = 0; with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { if(model->item_cnt > FILE_LIST_BUF_LEN) { if(dir < 0) { offset_new = model->item_idx - FILE_LIST_BUF_LEN / 4 * 3; @@ -262,8 +271,8 @@ void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) { offset_new = 0; } } - return false; - }); + }, + false); file_browser_worker_load(browser->worker, offset_new, FILE_LIST_BUF_LEN); } @@ -273,12 +282,14 @@ ArchiveFile_t* archive_get_current_file(ArchiveBrowserView* browser) { ArchiveFile_t* selected = NULL; with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { selected = files_array_size(model->files) ? files_array_get(model->files, model->item_idx - model->array_offset) : NULL; - return false; - }); + }, + false); return selected; } @@ -288,11 +299,13 @@ ArchiveFile_t* archive_get_file_at(ArchiveBrowserView* browser, size_t idx) { ArchiveFile_t* selected = NULL; with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { idx = CLAMP(idx - model->array_offset, files_array_size(model->files), 0u); selected = files_array_size(model->files) ? files_array_get(model->files, idx) : NULL; - return false; - }); + }, + false); return selected; } @@ -301,10 +314,7 @@ ArchiveTabEnum archive_get_tab(ArchiveBrowserView* browser) { ArchiveTabEnum tab_id = 0; with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { - tab_id = model->tab_idx; - return false; - }); + browser->view, ArchiveBrowserViewModel * model, { tab_id = model->tab_idx; }, false); return tab_id; } @@ -328,10 +338,7 @@ void archive_set_tab(ArchiveBrowserView* browser, ArchiveTabEnum tab) { furi_assert(browser); with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { - model->tab_idx = tab; - return false; - }); + browser->view, ArchiveBrowserViewModel * model, { model->tab_idx = tab; }, false); } void archive_add_app_item(ArchiveBrowserView* browser, const char* name) { @@ -344,11 +351,13 @@ void archive_add_app_item(ArchiveBrowserView* browser, const char* name) { archive_set_file_type(&item, name, false, true); with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { files_array_push_back(model->files, item); model->item_cnt = files_array_size(model->files); - return false; - }); + }, + false); ArchiveFile_t_clear(&item); } @@ -379,17 +388,19 @@ void archive_add_file_item(ArchiveBrowserView* browser, bool is_folder, const ch } } with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { - files_array_push_back(model->files, item); - return false; - }); + browser->view, + ArchiveBrowserViewModel * model, + { files_array_push_back(model->files, item); }, + false); ArchiveFile_t_clear(&item); } void archive_show_file_menu(ArchiveBrowserView* browser, bool show) { furi_assert(browser); with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { if(show) { if(archive_is_item_in_array(model, model->item_idx)) { model->menu = true; @@ -404,19 +415,15 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show) { model->menu = false; model->menu_idx = 0; } - - return true; - }); + }, + true); } void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) { furi_assert(browser); with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { - model->move_fav = active; - return true; - }); + browser->view, ArchiveBrowserViewModel * model, { model->move_fav = active; }, true); } static bool archive_is_dir_exists(FuriString* path) { @@ -477,11 +484,13 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { archive_switch_tab(browser, key); } else { with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { model->item_idx = 0; model->array_offset = 0; - return false; - }); + }, + false); archive_get_items(browser, furi_string_get_cstr(browser->path)); archive_update_offset(browser); } @@ -494,10 +503,7 @@ void archive_enter_dir(ArchiveBrowserView* browser, FuriString* path) { int32_t idx_temp = 0; with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { - idx_temp = model->item_idx; - return false; - }); + browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false); furi_string_set(browser->path, path); file_browser_worker_folder_enter(browser->worker, path, idx_temp); @@ -515,9 +521,6 @@ void archive_refresh_dir(ArchiveBrowserView* browser) { int32_t idx_temp = 0; with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { - idx_temp = model->item_idx; - return false; - }); + browser->view, ArchiveBrowserViewModel * model, { idx_temp = model->item_idx; }, false); file_browser_worker_folder_refresh(browser->worker, idx_temp); } diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index 0f9cd0723..cf25e7c89 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -358,11 +358,13 @@ static bool archive_view_input(InputEvent* event, void* context) { bool in_menu; bool move_fav_mode; with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { in_menu = model->menu; move_fav_mode = model->move_fav; - return false; - }); + }, + false); if(in_menu) { if(event->type != InputTypeShort) { @@ -370,24 +372,28 @@ static bool archive_view_input(InputEvent* event, void* context) { } if(event->key == InputKeyUp || event->key == InputKeyDown) { with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { size_t size_menu = menu_array_size(model->context_menu); if(event->key == InputKeyUp) { model->menu_idx = ((model->menu_idx - 1) + size_menu) % size_menu; } else if(event->key == InputKeyDown) { model->menu_idx = (model->menu_idx + 1) % size_menu; } - return true; - }); + }, + true); } else if(event->key == InputKeyOk) { uint32_t idx; with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { ArchiveContextMenuItem_t* current = menu_array_get(model->context_menu, model->menu_idx); idx = current->event; - return false; - }); + }, + false); browser->callback(idx, browser->context); } else if(event->key == InputKeyBack) { browser->callback(ArchiveBrowserEventFileMenuClose, browser->context); @@ -409,7 +415,9 @@ static bool archive_view_input(InputEvent* event, void* context) { if((event->key == InputKeyUp || event->key == InputKeyDown) && (event->type == InputTypeShort || event->type == InputTypeRepeat)) { with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { if(event->key == InputKeyUp) { model->item_idx = ((model->item_idx - 1) + model->item_cnt) % model->item_cnt; @@ -430,9 +438,8 @@ static bool archive_view_input(InputEvent* event, void* context) { browser->callback(ArchiveBrowserEventFavMoveDown, browser->context); } } - - return true; - }); + }, + true); archive_update_offset(browser); } @@ -480,12 +487,14 @@ ArchiveBrowserView* browser_alloc() { browser->path = furi_string_alloc_set(archive_get_default_path(TAB_DEFAULT)); with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { files_array_init(model->files); menu_array_init(model->context_menu); model->tab_idx = TAB_DEFAULT; - return true; - }); + }, + true); return browser; } @@ -498,11 +507,13 @@ void browser_free(ArchiveBrowserView* browser) { } with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { + browser->view, + ArchiveBrowserViewModel * model, + { files_array_clear(model->files); menu_array_clear(model->context_menu); - return false; - }); + }, + false); furi_string_free(browser->path); diff --git a/applications/main/bad_usb/bad_usb_script.c b/applications/main/bad_usb/bad_usb_script.c index f9d2a6b64..cfb0fa888 100644 --- a/applications/main/bad_usb/bad_usb_script.c +++ b/applications/main/bad_usb/bad_usb_script.c @@ -113,6 +113,7 @@ static const char ducky_cmd_string[] = {"STRING "}; static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "}; static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "}; static const char ducky_cmd_repeat[] = {"REPEAT "}; +static const char ducky_cmd_sysrq[] = {"SYSRQ "}; static const char ducky_cmd_altchar[] = {"ALTCHAR "}; static const char ducky_cmd_altstr_1[] = {"ALTSTRING "}; @@ -301,6 +302,14 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, FuriString* line) { line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt); return (state) ? (0) : SCRIPT_STATE_ERROR; + } else if(strncmp(line_tmp, ducky_cmd_sysrq, strlen(ducky_cmd_sysrq)) == 0) { + // SYSRQ + line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1]; + uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true); + furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN); + furi_hal_hid_kb_press(key); + furi_hal_hid_kb_release_all(); + return (0); } else { // Special keys + modifiers uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false); diff --git a/applications/main/bad_usb/views/bad_usb_view.c b/applications/main/bad_usb/views/bad_usb_view.c index 601ea453a..dda7aa8a1 100644 --- a/applications/main/bad_usb/views/bad_usb_view.c +++ b/applications/main/bad_usb/views/bad_usb_view.c @@ -166,37 +166,41 @@ void bad_usb_set_button_callback(BadUsb* bad_usb, BadUsbButtonCallback callback, furi_assert(bad_usb); furi_assert(callback); with_view_model( - bad_usb->view, (BadUsbModel * model) { + bad_usb->view, + BadUsbModel * model, + { UNUSED(model); bad_usb->callback = callback; bad_usb->context = context; - return true; - }); + }, + true); } void bad_usb_set_file_name(BadUsb* bad_usb, const char* name) { furi_assert(name); with_view_model( - bad_usb->view, (BadUsbModel * model) { - strlcpy(model->file_name, name, MAX_NAME_LEN); - return true; - }); + bad_usb->view, + BadUsbModel * model, + { strlcpy(model->file_name, name, MAX_NAME_LEN); }, + true); } void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) { furi_assert(layout); with_view_model( - bad_usb->view, (BadUsbModel * model) { - strlcpy(model->layout, layout, MAX_NAME_LEN); - return true; - }); + bad_usb->view, + BadUsbModel * model, + { strlcpy(model->layout, layout, MAX_NAME_LEN); }, + true); } void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) { furi_assert(st); with_view_model( - bad_usb->view, (BadUsbModel * model) { + bad_usb->view, + BadUsbModel * model, + { memcpy(&(model->state), st, sizeof(BadUsbState)); model->anim_frame ^= 1; - return true; - }); + }, + true); } diff --git a/applications/main/fap_loader/fap_loader_app.c b/applications/main/fap_loader/fap_loader_app.c index d2f6b1f41..6c909aeeb 100644 --- a/applications/main/fap_loader/fap_loader_app.c +++ b/applications/main/fap_loader/fap_loader_app.c @@ -182,6 +182,7 @@ int32_t fap_loader_app(void* p) { FapLoader* loader; if(p) { loader = fap_loader_alloc((const char*)p); + view_dispatcher_switch_to_view(loader->view_dispatcher, 0); fap_loader_run_selected_app(loader); } else { loader = fap_loader_alloc(EXT_PATH("apps")); diff --git a/applications/main/gpio/views/gpio_test.c b/applications/main/gpio/views/gpio_test.c index 89c09f864..69dc0f67b 100644 --- a/applications/main/gpio/views/gpio_test.c +++ b/applications/main/gpio/views/gpio_test.c @@ -48,23 +48,27 @@ static bool gpio_test_input_callback(InputEvent* event, void* context) { static bool gpio_test_process_left(GpioTest* gpio_test) { with_view_model( - gpio_test->view, (GpioTestModel * model) { + gpio_test->view, + GpioTestModel * model, + { if(model->pin_idx) { model->pin_idx--; } - return true; - }); + }, + true); return true; } static bool gpio_test_process_right(GpioTest* gpio_test) { with_view_model( - gpio_test->view, (GpioTestModel * model) { + gpio_test->view, + GpioTestModel * model, + { if(model->pin_idx < GPIO_ITEM_COUNT) { model->pin_idx++; } - return true; - }); + }, + true); return true; } @@ -72,7 +76,9 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) { bool consumed = false; with_view_model( - gpio_test->view, (GpioTestModel * model) { + gpio_test->view, + GpioTestModel * model, + { if(event->type == InputTypePress) { if(model->pin_idx < GPIO_ITEM_COUNT) { gpio_item_set_pin(model->pin_idx, true); @@ -89,8 +95,8 @@ static bool gpio_test_process_ok(GpioTest* gpio_test, InputEvent* event) { consumed = true; } gpio_test->callback(event->type, gpio_test->context); - return true; - }); + }, + true); return consumed; } @@ -122,10 +128,12 @@ void gpio_test_set_ok_callback(GpioTest* gpio_test, GpioTestOkCallback callback, furi_assert(gpio_test); furi_assert(callback); with_view_model( - gpio_test->view, (GpioTestModel * model) { + gpio_test->view, + GpioTestModel * model, + { UNUSED(model); gpio_test->callback = callback; gpio_test->context = context; - return false; - }); + }, + false); } diff --git a/applications/main/gpio/views/gpio_usb_uart.c b/applications/main/gpio/views/gpio_usb_uart.c index d190ecab0..c7406d29b 100644 --- a/applications/main/gpio/views/gpio_usb_uart.c +++ b/applications/main/gpio/views/gpio_usb_uart.c @@ -129,12 +129,14 @@ void gpio_usb_uart_set_callback(GpioUsbUart* usb_uart, GpioUsbUartCallback callb furi_assert(callback); with_view_model( - usb_uart->view, (GpioUsbUartModel * model) { + usb_uart->view, + GpioUsbUartModel * model, + { UNUSED(model); usb_uart->callback = callback; usb_uart->context = context; - return false; - }); + }, + false); } void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUartState* st) { @@ -143,7 +145,9 @@ void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUa furi_assert(st); with_view_model( - instance->view, (GpioUsbUartModel * model) { + instance->view, + GpioUsbUartModel * model, + { model->baudrate = st->baudrate_cur; model->vcp_port = cfg->vcp_ch; model->tx_pin = (cfg->uart_ch == 0) ? (13) : (15); @@ -152,6 +156,6 @@ void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUa model->rx_active = (model->rx_cnt != st->rx_cnt); model->tx_cnt = st->tx_cnt; model->rx_cnt = st->rx_cnt; - return true; - }); + }, + true); } diff --git a/applications/main/lfrfid/views/lfrfid_view_read.c b/applications/main/lfrfid/views/lfrfid_view_read.c index 66caf8df7..0d4db6178 100644 --- a/applications/main/lfrfid/views/lfrfid_view_read.c +++ b/applications/main/lfrfid/views/lfrfid_view_read.c @@ -56,19 +56,13 @@ static void lfrfid_view_read_draw_callback(Canvas* canvas, void* _model) { void lfrfid_view_read_enter(void* context) { LfRfidReadView* read_view = context; with_view_model( - read_view->view, (LfRfidReadViewModel * model) { - icon_animation_start(model->icon); - return true; - }); + read_view->view, LfRfidReadViewModel * model, { icon_animation_start(model->icon); }, true); } void lfrfid_view_read_exit(void* context) { LfRfidReadView* read_view = context; with_view_model( - read_view->view, (LfRfidReadViewModel * model) { - icon_animation_stop(model->icon); - return false; - }); + read_view->view, LfRfidReadViewModel * model, { icon_animation_stop(model->icon); }, false); } LfRfidReadView* lfrfid_view_read_alloc() { @@ -78,11 +72,13 @@ LfRfidReadView* lfrfid_view_read_alloc() { view_allocate_model(read_view->view, ViewModelTypeLocking, sizeof(LfRfidReadViewModel)); with_view_model( - read_view->view, (LfRfidReadViewModel * model) { + read_view->view, + LfRfidReadViewModel * model, + { model->icon = icon_animation_alloc(&A_Round_loader_8x8); view_tie_icon_animation(read_view->view, model->icon); - return false; - }); + }, + false); view_set_draw_callback(read_view->view, lfrfid_view_read_draw_callback); view_set_enter_callback(read_view->view, lfrfid_view_read_enter); @@ -93,10 +89,7 @@ LfRfidReadView* lfrfid_view_read_alloc() { void lfrfid_view_read_free(LfRfidReadView* read_view) { with_view_model( - read_view->view, (LfRfidReadViewModel * model) { - icon_animation_free(model->icon); - return false; - }); + read_view->view, LfRfidReadViewModel * model, { icon_animation_free(model->icon); }, false); view_free(read_view->view); free(read_view); @@ -108,10 +101,12 @@ View* lfrfid_view_read_get_view(LfRfidReadView* read_view) { void lfrfid_view_read_set_read_mode(LfRfidReadView* read_view, LfRfidReadViewMode mode) { with_view_model( - read_view->view, (LfRfidReadViewModel * model) { + read_view->view, + LfRfidReadViewModel * model, + { icon_animation_stop(model->icon); icon_animation_start(model->icon); model->read_mode = mode; - return true; - }); + }, + true); } diff --git a/applications/main/nfc/views/detect_reader.c b/applications/main/nfc/views/detect_reader.c index 9a0770438..2dbb4338b 100644 --- a/applications/main/nfc/views/detect_reader.c +++ b/applications/main/nfc/views/detect_reader.c @@ -64,10 +64,7 @@ static bool detect_reader_input_callback(InputEvent* event, void* context) { uint8_t nonces = 0; with_view_model( - detect_reader->view, (DetectReaderViewModel * model) { - nonces = model->nonces; - return false; - }); + detect_reader->view, DetectReaderViewModel * model, { nonces = model->nonces; }, false); if(event->type == InputTypeShort) { if(event->key == InputKeyOk) { @@ -103,12 +100,14 @@ void detect_reader_reset(DetectReader* detect_reader) { furi_assert(detect_reader); with_view_model( - detect_reader->view, (DetectReaderViewModel * model) { + detect_reader->view, + DetectReaderViewModel * model, + { model->nonces = 0; model->nonces_max = 0; model->state = DetectReaderStateStart; - return false; - }); + }, + false); } View* detect_reader_get_view(DetectReader* detect_reader) { @@ -132,27 +131,24 @@ void detect_reader_set_nonces_max(DetectReader* detect_reader, uint16_t nonces_m furi_assert(detect_reader); with_view_model( - detect_reader->view, (DetectReaderViewModel * model) { - model->nonces_max = nonces_max; - return false; - }); + detect_reader->view, + DetectReaderViewModel * model, + { model->nonces_max = nonces_max; }, + false); } void detect_reader_set_nonces_collected(DetectReader* detect_reader, uint16_t nonces_collected) { furi_assert(detect_reader); with_view_model( - detect_reader->view, (DetectReaderViewModel * model) { - model->nonces = nonces_collected; - return false; - }); + detect_reader->view, + DetectReaderViewModel * model, + { model->nonces = nonces_collected; }, + false); } void detect_reader_set_state(DetectReader* detect_reader, DetectReaderState state) { furi_assert(detect_reader); with_view_model( - detect_reader->view, (DetectReaderViewModel * model) { - model->state = state; - return true; - }); + detect_reader->view, DetectReaderViewModel * model, { model->state = state; }, true); } diff --git a/applications/main/nfc/views/dict_attack.c b/applications/main/nfc/views/dict_attack.c index cbafbf69a..c5f55ae76 100644 --- a/applications/main/nfc/views/dict_attack.c +++ b/applications/main/nfc/views/dict_attack.c @@ -80,20 +80,20 @@ DictAttack* dict_attack_alloc() { view_set_input_callback(dict_attack->view, dict_attack_input_callback); view_set_context(dict_attack->view, dict_attack); with_view_model( - dict_attack->view, (DictAttackViewModel * model) { - model->header = furi_string_alloc(); - return false; - }); + dict_attack->view, + DictAttackViewModel * model, + { model->header = furi_string_alloc(); }, + false); return dict_attack; } void dict_attack_free(DictAttack* dict_attack) { furi_assert(dict_attack); with_view_model( - dict_attack->view, (DictAttackViewModel * model) { - furi_string_free(model->header); - return false; - }); + dict_attack->view, + DictAttackViewModel * model, + { furi_string_free(model->header); }, + false); view_free(dict_attack->view); free(dict_attack); } @@ -101,7 +101,9 @@ void dict_attack_free(DictAttack* dict_attack) { void dict_attack_reset(DictAttack* dict_attack) { furi_assert(dict_attack); with_view_model( - dict_attack->view, (DictAttackViewModel * model) { + dict_attack->view, + DictAttackViewModel * model, + { model->state = DictAttackStateRead; model->type = MfClassicType1k; model->sectors_total = 0; @@ -112,8 +114,8 @@ void dict_attack_reset(DictAttack* dict_attack) { model->dict_keys_total = 0; model->dict_keys_current = 0; furi_string_reset(model->header); - return false; - }); + }, + false); } View* dict_attack_get_view(DictAttack* dict_attack) { @@ -133,99 +135,103 @@ void dict_attack_set_header(DictAttack* dict_attack, const char* header) { furi_assert(header); with_view_model( - dict_attack->view, (DictAttackViewModel * model) { - furi_string_set(model->header, header); - return true; - }); + dict_attack->view, + DictAttackViewModel * model, + { furi_string_set(model->header, header); }, + true); } void dict_attack_set_card_detected(DictAttack* dict_attack, MfClassicType type) { furi_assert(dict_attack); with_view_model( - dict_attack->view, (DictAttackViewModel * model) { + dict_attack->view, + DictAttackViewModel * model, + { model->state = DictAttackStateRead; model->sectors_total = mf_classic_get_total_sectors_num(type); model->keys_total = model->sectors_total * 2; - return true; - }); + }, + true); } void dict_attack_set_card_removed(DictAttack* dict_attack) { furi_assert(dict_attack); with_view_model( - dict_attack->view, (DictAttackViewModel * model) { - model->state = DictAttackStateCardRemoved; - return true; - }); + dict_attack->view, + DictAttackViewModel * model, + { model->state = DictAttackStateCardRemoved; }, + true); } void dict_attack_set_sector_read(DictAttack* dict_attack, uint8_t sec_read) { furi_assert(dict_attack); with_view_model( - dict_attack->view, (DictAttackViewModel * model) { - model->sectors_read = sec_read; - return true; - }); + dict_attack->view, DictAttackViewModel * model, { model->sectors_read = sec_read; }, true); } void dict_attack_set_keys_found(DictAttack* dict_attack, uint8_t keys_found) { furi_assert(dict_attack); with_view_model( - dict_attack->view, (DictAttackViewModel * model) { - model->keys_found = keys_found; - return true; - }); + dict_attack->view, DictAttackViewModel * model, { model->keys_found = keys_found; }, true); } void dict_attack_set_current_sector(DictAttack* dict_attack, uint8_t curr_sec) { furi_assert(dict_attack); with_view_model( - dict_attack->view, (DictAttackViewModel * model) { + dict_attack->view, + DictAttackViewModel * model, + { model->sector_current = curr_sec; model->dict_keys_current = 0; - return true; - }); + }, + true); } void dict_attack_inc_current_sector(DictAttack* dict_attack) { furi_assert(dict_attack); with_view_model( - dict_attack->view, (DictAttackViewModel * model) { + dict_attack->view, + DictAttackViewModel * model, + { if(model->sector_current < model->sectors_total) { model->sector_current++; model->dict_keys_current = 0; } - return true; - }); + }, + true); } void dict_attack_inc_keys_found(DictAttack* dict_attack) { furi_assert(dict_attack); with_view_model( - dict_attack->view, (DictAttackViewModel * model) { + dict_attack->view, + DictAttackViewModel * model, + { if(model->keys_found < model->keys_total) { model->keys_found++; } - return true; - }); + }, + true); } void dict_attack_set_total_dict_keys(DictAttack* dict_attack, uint16_t dict_keys_total) { furi_assert(dict_attack); with_view_model( - dict_attack->view, (DictAttackViewModel * model) { - model->dict_keys_total = dict_keys_total; - return true; - }); + dict_attack->view, + DictAttackViewModel * model, + { model->dict_keys_total = dict_keys_total; }, + true); } void dict_attack_inc_current_dict_key(DictAttack* dict_attack, uint16_t keys_tried) { furi_assert(dict_attack); with_view_model( - dict_attack->view, (DictAttackViewModel * model) { + dict_attack->view, + DictAttackViewModel * model, + { if(model->dict_keys_current + keys_tried < model->dict_keys_total) { model->dict_keys_current += keys_tried; } - return true; - }); + }, + true); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver.c b/applications/main/subghz/scenes/subghz_scene_receiver.c index 8333f5343..cafa8b927 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver.c @@ -167,6 +167,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) { subghz_sleep(subghz); } subghz->txrx->hopper_state = SubGhzHopperStateOFF; + subghz_history_set_hopper_state(subghz->txrx->history, false); subghz->txrx->idx_menu_chosen = 0; subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz); diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index ab5cde516..f3664a46a 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -189,64 +189,64 @@ static void subghz_scene_receiver_config_set_detect_raw(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - if(subghz->txrx->hopper_state == 0) { - variable_item_set_current_value_text(item, detect_raw_text[index]); + //if(subghz->txrx->hopper_state == 0) { + variable_item_set_current_value_text(item, detect_raw_text[index]); #ifdef SUBGHZ_SAVE_DETECT_RAW_SETTING - subghz->last_settings->detect_raw = index; + subghz->last_settings->detect_raw = index; - subghz_last_settings_set_detect_raw_values(subghz); + subghz_last_settings_set_detect_raw_values(subghz); #else - subghz_receiver_set_filter(subghz->txrx->receiver, detect_raw_value[index]); + subghz_receiver_set_filter(subghz->txrx->receiver, detect_raw_value[index]); - subghz_protocol_decoder_raw_set_auto_mode( - subghz_receiver_search_decoder_base_by_name( - subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME), - (index == 1)); + subghz_protocol_decoder_raw_set_auto_mode( + subghz_receiver_search_decoder_base_by_name( + subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME), + (index == 1)); #endif - } else { + /*} else { variable_item_set_current_value_index(item, 0); - } + }*/ } static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) { SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - if(subghz_receiver_get_filter(subghz->txrx->receiver) == SubGhzProtocolFlag_Decodable) { - variable_item_set_current_value_text(item, hopping_text[index]); - if(hopping_value[index] == SubGhzHopperStateOFF) { - char text_buf[10] = {0}; - snprintf( - text_buf, - sizeof(text_buf), - "%lu.%02lu", - subghz_setting_get_default_frequency(subghz->setting) / 1000000, - (subghz_setting_get_default_frequency(subghz->setting) % 1000000) / 10000); - variable_item_set_current_value_text( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - text_buf); - subghz->txrx->preset->frequency = - subghz_setting_get_default_frequency(subghz->setting); - variable_item_set_current_value_index( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz->setting)); - } else { - variable_item_set_current_value_text( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - " -----"); - variable_item_set_current_value_index( - (VariableItem*)scene_manager_get_scene_state( - subghz->scene_manager, SubGhzSceneReceiverConfig), - subghz_setting_get_frequency_default_index(subghz->setting)); - } - - subghz->txrx->hopper_state = hopping_value[index]; + //if(subghz_receiver_get_filter(subghz->txrx->receiver) == SubGhzProtocolFlag_Decodable) { + variable_item_set_current_value_text(item, hopping_text[index]); + if(hopping_value[index] == SubGhzHopperStateOFF) { + char text_buf[10] = {0}; + snprintf( + text_buf, + sizeof(text_buf), + "%lu.%02lu", + subghz_setting_get_default_frequency(subghz->setting) / 1000000, + (subghz_setting_get_default_frequency(subghz->setting) % 1000000) / 10000); + variable_item_set_current_value_text( + (VariableItem*)scene_manager_get_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig), + text_buf); + subghz->txrx->preset->frequency = subghz_setting_get_default_frequency(subghz->setting); + variable_item_set_current_value_index( + (VariableItem*)scene_manager_get_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig), + subghz_setting_get_frequency_default_index(subghz->setting)); } else { - variable_item_set_current_value_index(item, 0); + variable_item_set_current_value_text( + (VariableItem*)scene_manager_get_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig), + " -----"); + variable_item_set_current_value_index( + (VariableItem*)scene_manager_get_scene_state( + subghz->scene_manager, SubGhzSceneReceiverConfig), + subghz_setting_get_frequency_default_index(subghz->setting)); } + + subghz->txrx->hopper_state = hopping_value[index]; + subghz_history_set_hopper_state(subghz->txrx->history, (index == 1)); + /*} else { + variable_item_set_current_value_index(item, 0); + }*/ } static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { diff --git a/applications/main/subghz/subghz_history.c b/applications/main/subghz/subghz_history.c index c8c733476..9a42fc9bb 100644 --- a/applications/main/subghz/subghz_history.c +++ b/applications/main/subghz/subghz_history.c @@ -3,7 +3,7 @@ #include #include -#define SUBGHZ_HISTORY_MAX 65 +#define SUBGHZ_HISTORY_MAX 60 /** * @brief Settings for temporary files @@ -41,6 +41,7 @@ struct SubGhzHistory { uint8_t code_last_hash_data; FuriString* tmp_string; bool write_tmp_files; + bool is_hopper_running; Storage* storage; SubGhzHistoryStruct* history; }; @@ -134,6 +135,8 @@ SubGhzHistory* subghz_history_alloc(void) { instance->storage = furi_record_open(RECORD_STORAGE); instance->write_tmp_files = subghz_history_check_sdcard(instance); + instance->is_hopper_running = false; + if(!instance->write_tmp_files) { FURI_LOG_E(TAG, "Unstable work! Cannot use SD Card!"); } @@ -209,6 +212,12 @@ void subghz_history_reset(SubGhzHistory* instance) { instance->code_last_hash_data = 0; } +void subghz_history_set_hopper_state(SubGhzHistory* instance, bool hopper_state) { + furi_assert(instance); + + instance->is_hopper_running = hopper_state; +} + uint16_t subghz_history_get_item(SubGhzHistory* instance) { furi_assert(instance); return instance->last_index_write; @@ -354,16 +363,23 @@ bool subghz_history_add_to_history( item->protocol_name, "%s", furi_string_get_cstr(instance->tmp_string)); } if(!strcmp(furi_string_get_cstr(instance->tmp_string), "RAW")) { + // Check if hopper enabled we need to add little delay + if(instance->is_hopper_running) { + furi_delay_ms(40); + } + // Enable writing temp files to micro sd + tmp_file_for_raw = true; + // Write display name furi_string_printf( item->item_str, "RAW %03ld.%02ld", preset->frequency / 1000000 % 1000, preset->frequency / 10000 % 100); - + // Rewind if(!flipper_format_rewind(item->flipper_string)) { FURI_LOG_E(TAG, "Rewind error"); } - tmp_file_for_raw = true; + break; } else if(!strcmp(furi_string_get_cstr(instance->tmp_string), "KeeLoq")) { furi_string_set(instance->tmp_string, "KL "); diff --git a/applications/main/subghz/subghz_history.h b/applications/main/subghz/subghz_history.h index 7bff3df5e..6ab3603d8 100644 --- a/applications/main/subghz/subghz_history.h +++ b/applications/main/subghz/subghz_history.h @@ -103,3 +103,10 @@ bool subghz_history_add_to_history( * @return SubGhzProtocolCommonLoad* */ FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx); + +/** Set hopper state for internal usage in history + * + * @param instance - SubGhzHistory instance + * @param hopper_state - bool is hopper running? + */ +void subghz_history_set_hopper_state(SubGhzHistory* instance, bool hopper_state); diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index 5355df463..05c6e7908 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -68,10 +68,7 @@ void subghz_view_receiver_set_mode( SubGhzViewReceiver* subghz_receiver, SubGhzViewReceiverMode mode) { with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { - model->mode = mode; - return true; - }); + subghz_receiver->view, SubGhzViewReceiverModel * model, { model->mode = mode; }, true); } void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock lock) { @@ -80,17 +77,17 @@ void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLo if(lock == SubGhzLockOn) { subghz_receiver->lock = lock; with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { - model->bar_show = SubGhzViewReceiverBarShowLock; - return true; - }); + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { model->bar_show = SubGhzViewReceiverBarShowLock; }, + true); furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(1000)); } else { with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { - model->bar_show = SubGhzViewReceiverBarShowDefault; - return true; - }); + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { model->bar_show = SubGhzViewReceiverBarShowDefault; }, + true); } } @@ -108,7 +105,9 @@ static void subghz_view_receiver_update_offset(SubGhzViewReceiver* subghz_receiv furi_assert(subghz_receiver); with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { size_t history_item = model->history_item; uint16_t bounds = history_item > 3 ? 2 : history_item; @@ -120,8 +119,8 @@ static void subghz_view_receiver_update_offset(SubGhzViewReceiver* subghz_receiv } else if(model->list_offset > model->idx - bounds) { model->list_offset = CLAMP(model->idx - 1, (int16_t)(history_item - bounds), 0); } - return true; - }); + }, + true); } void subghz_view_receiver_add_item_to_menu( @@ -130,7 +129,9 @@ void subghz_view_receiver_add_item_to_menu( uint8_t type) { furi_assert(subghz_receiver); with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { SubGhzReceiverMenuItem* item_menu = SubGhzReceiverMenuItemArray_push_raw(model->history->data); item_menu->item_str = furi_string_alloc_set(name); @@ -141,9 +142,8 @@ void subghz_view_receiver_add_item_to_menu( } else { model->history_item++; } - - return true; - }); + }, + true); subghz_view_receiver_update_offset(subghz_receiver); } @@ -154,12 +154,14 @@ void subghz_view_receiver_add_data_statusbar( const char* history_stat_str) { furi_assert(subghz_receiver); with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { furi_string_set(model->frequency_str, frequency_str); furi_string_set(model->preset_str, preset_str); furi_string_set(model->history_stat_str, history_stat_str); - return true; - }); + }, + true); } void subghz_view_receiver_add_data_progress( @@ -167,10 +169,10 @@ void subghz_view_receiver_add_data_progress( const char* progress_str) { furi_assert(subghz_receiver); with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { - furi_string_set(model->progress_str, progress_str); - return true; - }); + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { furi_string_set(model->progress_str, progress_str); }, + true); } static void subghz_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) { @@ -275,10 +277,10 @@ static void subghz_view_receiver_timer_callback(void* context) { furi_assert(context); SubGhzViewReceiver* subghz_receiver = context; with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { - model->bar_show = SubGhzViewReceiverBarShowDefault; - return true; - }); + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { model->bar_show = SubGhzViewReceiverBarShowDefault; }, + true); if(subghz_receiver->lock_count < UNLOCK_CNT) { subghz_receiver->callback( SubGhzCustomEventViewReceiverOffDisplay, subghz_receiver->context); @@ -295,10 +297,10 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { if(subghz_receiver->lock == SubGhzLockOn) { with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { - model->bar_show = SubGhzViewReceiverBarShowToUnlockPress; - return true; - }); + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { model->bar_show = SubGhzViewReceiverBarShowToUnlockPress; }, + true); if(subghz_receiver->lock_count == 0) { furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(1000)); } @@ -309,10 +311,10 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { // subghz_receiver->callback( // SubGhzCustomEventViewReceiverUnlock, subghz_receiver->context); with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { - model->bar_show = SubGhzViewReceiverBarShowUnlock; - return true; - }); + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { model->bar_show = SubGhzViewReceiverBarShowUnlock; }, + true); //subghz_receiver->lock = SubGhzLockOff; furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(650)); } @@ -326,29 +328,35 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) { event->key == InputKeyUp && (event->type == InputTypeShort || event->type == InputTypeRepeat)) { with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { if(model->idx != 0) model->idx--; - return true; - }); + }, + true); } else if( event->key == InputKeyDown && (event->type == InputTypeShort || event->type == InputTypeRepeat)) { with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { if(model->idx != model->history_item - 1) model->idx++; - return true; - }); + }, + true); } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { subghz_receiver->callback(SubGhzCustomEventViewReceiverConfig, subghz_receiver->context); } else if(event->key == InputKeyOk && event->type == InputTypeShort) { with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { if(model->history_item != 0) { subghz_receiver->callback( SubGhzCustomEventViewReceiverOK, subghz_receiver->context); } - return false; - }); + }, + false); } subghz_view_receiver_update_offset(subghz_receiver); @@ -364,7 +372,9 @@ void subghz_view_receiver_exit(void* context) { furi_assert(context); SubGhzViewReceiver* subghz_receiver = context; with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { furi_string_reset(model->frequency_str); furi_string_reset(model->preset_str); furi_string_reset(model->history_stat_str); @@ -378,8 +388,8 @@ void subghz_view_receiver_exit(void* context) { model->idx = 0; model->list_offset = 0; model->history_item = 0; - return false; - }); + }, + false); furi_timer_stop(subghz_receiver->timer); } @@ -400,7 +410,9 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() { view_set_exit_callback(subghz_receiver->view, subghz_view_receiver_exit); with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { model->frequency_str = furi_string_alloc(); model->preset_str = furi_string_alloc(); model->history_stat_str = furi_string_alloc(); @@ -408,8 +420,8 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() { model->bar_show = SubGhzViewReceiverBarShowDefault; model->history = malloc(sizeof(SubGhzReceiverHistory)); SubGhzReceiverMenuItemArray_init(model->history->data); - return true; - }); + }, + true); subghz_receiver->timer = furi_timer_alloc(subghz_view_receiver_timer_callback, FuriTimerTypeOnce, subghz_receiver); return subghz_receiver; @@ -419,7 +431,9 @@ void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver) { furi_assert(subghz_receiver); with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { furi_string_free(model->frequency_str); furi_string_free(model->preset_str); furi_string_free(model->history_stat_str); @@ -431,8 +445,8 @@ void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver) { } SubGhzReceiverMenuItemArray_clear(model->history->data); free(model->history); - return false; - }); + }, + false); furi_timer_free(subghz_receiver->timer); view_free(subghz_receiver->view); free(subghz_receiver); @@ -447,20 +461,19 @@ uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver) furi_assert(subghz_receiver); uint32_t idx = 0; with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { - idx = model->idx; - return false; - }); + subghz_receiver->view, SubGhzViewReceiverModel * model, { idx = model->idx; }, false); return idx; } void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx) { furi_assert(subghz_receiver); with_view_model( - subghz_receiver->view, (SubGhzViewReceiverModel * model) { + subghz_receiver->view, + SubGhzViewReceiverModel * model, + { model->idx = idx; if(model->idx > 2) model->list_offset = idx - 2; - return true; - }); + }, + true); subghz_view_receiver_update_offset(subghz_receiver); } diff --git a/applications/main/subghz/views/subghz_frequency_analyzer.c b/applications/main/subghz/views/subghz_frequency_analyzer.c index 677cd91ae..53f0c8dd0 100644 --- a/applications/main/subghz/views/subghz_frequency_analyzer.c +++ b/applications/main/subghz/views/subghz_frequency_analyzer.c @@ -277,7 +277,9 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { if(event->key == InputKeyOk) { bool updated = false; with_view_model( - instance->view, (SubGhzFrequencyAnalyzerModel * model) { + instance->view, + SubGhzFrequencyAnalyzerModel * model, + { uint32_t prev_freq_to_save = model->frequency_to_save; uint32_t frequency_candidate = 0; if(model->frequency != 0) { @@ -305,8 +307,8 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { notification_message(instance->notifications, &sequence_hw_blink); updated = true; } - return true; - }); + }, + true); #ifdef FURI_DEBUG FURI_LOG_I( @@ -340,14 +342,16 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) { if(need_redraw) { SubGhzFrequencyAnalyzer* instance = context; with_view_model( - instance->view, (SubGhzFrequencyAnalyzerModel * model) { + instance->view, + SubGhzFrequencyAnalyzerModel * model, + { model->rssi_last = instance->rssi_last; model->frequency_last = instance->frequency_last; model->trigger = subghz_frequency_analyzer_worker_get_trigger_level(instance->worker); model->feedback_level = instance->feedback_level; - return true; - }); + }, + true); } return true; @@ -406,15 +410,17 @@ void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency, instance->locked = (rssi != 0.f); with_view_model( - instance->view, (SubGhzFrequencyAnalyzerModel * model) { + instance->view, + SubGhzFrequencyAnalyzerModel * model, + { model->rssi = rssi; model->rssi_last = instance->rssi_last; model->frequency = frequency; model->frequency_last = instance->frequency_last_vis; model->trigger = subghz_frequency_analyzer_worker_get_trigger_level(instance->worker); model->feedback_level = instance->feedback_level; - return true; - }); + }, + true); } void subghz_frequency_analyzer_enter(void* context) { @@ -441,15 +447,17 @@ void subghz_frequency_analyzer_enter(void* context) { subghz_frequency_analyzer_worker_set_trigger_level(instance->worker, RSSI_MIN); with_view_model( - instance->view, (SubGhzFrequencyAnalyzerModel * model) { + instance->view, + SubGhzFrequencyAnalyzerModel * model, + { model->rssi = 0; model->rssi_last = 0; model->frequency = 0; model->frequency_last = 0; model->frequency_to_save = 0; model->trigger = RSSI_MIN; - return true; - }); + }, + true); } void subghz_frequency_analyzer_exit(void* context) { @@ -503,10 +511,10 @@ uint32_t subghz_frequency_analyzer_get_frequency_to_save(SubGhzFrequencyAnalyzer furi_assert(instance); uint32_t frequency; with_view_model( - instance->view, (SubGhzFrequencyAnalyzerModel * model) { - frequency = model->frequency_to_save; - return false; - }); + instance->view, + SubGhzFrequencyAnalyzerModel * model, + { frequency = model->frequency_to_save; }, + false); return frequency; } \ No newline at end of file diff --git a/applications/main/subghz/views/subghz_read_raw.c b/applications/main/subghz/views/subghz_read_raw.c index 1b1d3c8c9..759798f90 100644 --- a/applications/main/subghz/views/subghz_read_raw.c +++ b/applications/main/subghz/views/subghz_read_raw.c @@ -46,11 +46,13 @@ void subghz_read_raw_add_data_statusbar( const char* preset_str) { furi_assert(instance); with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { furi_string_set(model->frequency_str, frequency_str); furi_string_set(model->preset_str, preset_str); - return true; - }); + }, + true); } void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi) { @@ -64,31 +66,35 @@ void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi) { } with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { model->rssi_history[model->ind_write++] = u_rssi; if(model->ind_write > SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE) { model->rssi_history_end = true; model->ind_write = 0; } - return true; - }); + }, + true); } void subghz_read_raw_update_sample_write(SubGhzReadRAW* instance, size_t sample) { furi_assert(instance); with_view_model( - instance->view, (SubGhzReadRAWModel * model) { - furi_string_printf(model->sample_write, "%d spl.", sample); - return false; - }); + instance->view, + SubGhzReadRAWModel * model, + { furi_string_printf(model->sample_write, "%d spl.", sample); }, + false); } void subghz_read_raw_stop_send(SubGhzReadRAW* instance) { furi_assert(instance); with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { switch(model->status) { case SubGhzReadRAWStatusTXRepeat: case SubGhzReadRAWStatusLoadKeyTXRepeat: @@ -106,19 +112,21 @@ void subghz_read_raw_stop_send(SubGhzReadRAW* instance) { model->status = SubGhzReadRAWStatusIDLE; break; } - return true; - }); + }, + true); } void subghz_read_raw_update_sin(SubGhzReadRAW* instance) { furi_assert(instance); with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { if(model->ind_sin++ > 62) { model->ind_sin = 0; } - return true; - }); + }, + true); } static int8_t subghz_read_raw_tab_sin(uint8_t x) { @@ -289,9 +297,11 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { //further check of events is not needed, we exit return false; } else if(event->key == InputKeyOk && event->type == InputTypePress) { + uint8_t ret = false; with_view_model( - instance->view, (SubGhzReadRAWModel * model) { - uint8_t ret = false; + instance->view, + SubGhzReadRAWModel * model, + { switch(model->status) { case SubGhzReadRAWStatusIDLE: // Start TX @@ -317,11 +327,13 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { default: break; } - return ret; - }); + }, + ret); } else if(event->key == InputKeyOk && event->type == InputTypeRelease) { with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { if(model->status == SubGhzReadRAWStatusTXRepeat) { // Stop repeat TX model->status = SubGhzReadRAWStatusTX; @@ -329,11 +341,13 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { // Stop repeat TX model->status = SubGhzReadRAWStatusLoadKeyTX; } - return false; - }); + }, + false); } else if(event->key == InputKeyBack && event->type == InputTypeShort) { with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { switch(model->status) { case SubGhzReadRAWStatusREC: //Stop REC @@ -360,11 +374,13 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { instance->callback(SubGhzCustomEventViewReadRAWBack, instance->context); break; } - return true; - }); + }, + true); } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { if(!model->raw_send_only) { if(model->status == SubGhzReadRAWStatusStart) { //Config @@ -381,11 +397,13 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { instance->callback(SubGhzCustomEventViewReadRAWErase, instance->context); } } - return true; - }); + }, + true); } else if(event->key == InputKeyRight && event->type == InputTypeShort) { with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { if(!model->raw_send_only) { if(model->status == SubGhzReadRAWStatusIDLE) { //Save @@ -395,11 +413,13 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { instance->callback(SubGhzCustomEventViewReadRAWMore, instance->context); } } - return true; - }); + }, + true); } else if(event->key == InputKeyOk && event->type == InputTypeShort) { with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { if(model->status == SubGhzReadRAWStatusStart) { //Record instance->callback(SubGhzCustomEventViewReadRAWREC, instance->context); @@ -411,8 +431,8 @@ bool subghz_read_raw_input(InputEvent* event, void* context) { instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context); model->status = SubGhzReadRAWStatusIDLE; } - return true; - }); + }, + true); } return true; } @@ -426,36 +446,42 @@ void subghz_read_raw_set_status( switch(status) { case SubGhzReadRAWStatusStart: with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { model->status = SubGhzReadRAWStatusStart; model->rssi_history_end = false; model->ind_write = 0; furi_string_reset(model->file_name); furi_string_set(model->sample_write, "0 spl."); - return true; - }); + }, + true); break; case SubGhzReadRAWStatusIDLE: with_view_model( - instance->view, (SubGhzReadRAWModel * model) { - model->status = SubGhzReadRAWStatusIDLE; - return true; - }); + instance->view, + SubGhzReadRAWModel * model, + { model->status = SubGhzReadRAWStatusIDLE; }, + true); break; case SubGhzReadRAWStatusLoadKeyTX: with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { model->status = SubGhzReadRAWStatusLoadKeyIDLE; model->rssi_history_end = false; model->ind_write = 0; furi_string_set(model->file_name, file_name); furi_string_set(model->sample_write, "RAW"); - return true; - }); + }, + true); break; case SubGhzReadRAWStatusSaveKey: with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { model->status = SubGhzReadRAWStatusLoadKeyIDLE; if(!model->ind_write) { furi_string_set(model->file_name, file_name); @@ -463,8 +489,8 @@ void subghz_read_raw_set_status( } else { furi_string_reset(model->file_name); } - return true; - }); + }, + true); break; default: @@ -483,15 +509,17 @@ void subghz_read_raw_exit(void* context) { SubGhzReadRAW* instance = context; with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { if(model->status != SubGhzReadRAWStatusIDLE && model->status != SubGhzReadRAWStatusStart && model->status != SubGhzReadRAWStatusLoadKeyIDLE) { instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context); model->status = SubGhzReadRAWStatusStart; } - return true; - }); + }, + true); } SubGhzReadRAW* subghz_read_raw_alloc(bool raw_send_only) { @@ -507,15 +535,17 @@ SubGhzReadRAW* subghz_read_raw_alloc(bool raw_send_only) { view_set_exit_callback(instance->view, subghz_read_raw_exit); with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { model->frequency_str = furi_string_alloc(); model->preset_str = furi_string_alloc(); model->sample_write = furi_string_alloc(); model->file_name = furi_string_alloc(); model->raw_send_only = raw_send_only; model->rssi_history = malloc(SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE * sizeof(uint8_t)); - return true; - }); + }, + true); return instance; } @@ -524,14 +554,16 @@ void subghz_read_raw_free(SubGhzReadRAW* instance) { furi_assert(instance); with_view_model( - instance->view, (SubGhzReadRAWModel * model) { + instance->view, + SubGhzReadRAWModel * model, + { furi_string_free(model->frequency_str); furi_string_free(model->preset_str); furi_string_free(model->sample_write); furi_string_free(model->file_name); free(model->rssi_history); - return true; - }); + }, + true); view_free(instance->view); free(instance); } diff --git a/applications/main/subghz/views/subghz_test_carrier.c b/applications/main/subghz/views/subghz_test_carrier.c index 6729eaad8..e533a6aac 100644 --- a/applications/main/subghz/views/subghz_test_carrier.c +++ b/applications/main/subghz/views/subghz_test_carrier.c @@ -89,7 +89,9 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) { } with_view_model( - subghz_test_carrier->view, (SubGhzTestCarrierModel * model) { + subghz_test_carrier->view, + SubGhzTestCarrierModel * model, + { furi_hal_subghz_idle(); if(event->key == InputKeyLeft) { @@ -125,9 +127,8 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) { SubGhzTestCarrierEventOnlyRx, subghz_test_carrier->context); } } - - return true; - }); + }, + true); return true; } @@ -142,15 +143,17 @@ void subghz_test_carrier_enter(void* context) { furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow); with_view_model( - subghz_test_carrier->view, (SubGhzTestCarrierModel * model) { + subghz_test_carrier->view, + SubGhzTestCarrierModel * model, + { model->frequency = subghz_frequencies_433_92_testing; // 433 model->real_frequency = furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); model->path = FuriHalSubGhzPathIsolate; // isolate model->rssi = 0.0f; model->status = SubGhzTestCarrierModelStatusRx; - return true; - }); + }, + true); furi_hal_subghz_rx(); @@ -172,13 +175,14 @@ void subghz_test_carrier_rssi_timer_callback(void* context) { SubGhzTestCarrier* subghz_test_carrier = context; with_view_model( - subghz_test_carrier->view, (SubGhzTestCarrierModel * model) { + subghz_test_carrier->view, + SubGhzTestCarrierModel * model, + { if(model->status == SubGhzTestCarrierModelStatusRx) { model->rssi = furi_hal_subghz_get_rssi(); - return true; } - return false; - }); + }, + false); } SubGhzTestCarrier* subghz_test_carrier_alloc() { diff --git a/applications/main/subghz/views/subghz_test_packet.c b/applications/main/subghz/views/subghz_test_packet.c index c83aebec9..a42898f77 100644 --- a/applications/main/subghz/views/subghz_test_packet.c +++ b/applications/main/subghz/views/subghz_test_packet.c @@ -68,7 +68,9 @@ static void subghz_test_packet_rssi_timer_callback(void* context) { SubGhzTestPacket* instance = context; with_view_model( - instance->view, (SubGhzTestPacketModel * model) { + instance->view, + SubGhzTestPacketModel * model, + { if(model->status == SubGhzTestPacketModelStatusRx) { model->rssi = furi_hal_subghz_get_rssi(); model->packets = instance->packet_rx; @@ -77,8 +79,8 @@ static void subghz_test_packet_rssi_timer_callback(void* context) { SUBGHZ_TEST_PACKET_COUNT - subghz_encoder_princeton_for_testing_get_repeat_left(instance->encoder); } - return true; - }); + }, + true); } static void subghz_test_packet_draw(Canvas* canvas, SubGhzTestPacketModel* model) { @@ -137,7 +139,9 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) { } with_view_model( - instance->view, (SubGhzTestPacketModel * model) { + instance->view, + SubGhzTestPacketModel * model, + { if(model->status == SubGhzTestPacketModelStatusRx) { furi_hal_subghz_stop_async_rx(); } else if(model->status == SubGhzTestPacketModelStatusTx) { @@ -179,9 +183,8 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) { instance->callback(SubGhzTestPacketEventOnlyRx, instance->context); } } - - return true; - }); + }, + true); return true; } @@ -194,15 +197,17 @@ void subghz_test_packet_enter(void* context) { furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); with_view_model( - instance->view, (SubGhzTestPacketModel * model) { + instance->view, + SubGhzTestPacketModel * model, + { model->frequency = subghz_frequencies_433_92_testing; model->real_frequency = furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]); model->path = FuriHalSubGhzPathIsolate; // isolate model->rssi = 0.0f; model->status = SubGhzTestPacketModelStatusRx; - return true; - }); + }, + true); furi_hal_subghz_start_async_rx(subghz_test_packet_rx_callback, instance); @@ -217,15 +222,17 @@ void subghz_test_packet_exit(void* context) { // Reinitialize IC to default state with_view_model( - instance->view, (SubGhzTestPacketModel * model) { + instance->view, + SubGhzTestPacketModel * model, + { if(model->status == SubGhzTestPacketModelStatusRx) { furi_hal_subghz_stop_async_rx(); } else if(model->status == SubGhzTestPacketModelStatusTx) { subghz_encoder_princeton_for_testing_stop(instance->encoder, furi_get_tick()); furi_hal_subghz_stop_async_tx(); } - return true; - }); + }, + true); furi_hal_subghz_sleep(); } diff --git a/applications/main/subghz/views/subghz_test_static.c b/applications/main/subghz/views/subghz_test_static.c index 7af54c3c0..6abefda76 100644 --- a/applications/main/subghz/views/subghz_test_static.c +++ b/applications/main/subghz/views/subghz_test_static.c @@ -77,7 +77,9 @@ bool subghz_test_static_input(InputEvent* event, void* context) { } with_view_model( - instance->view, (SubGhzTestStaticModel * model) { + instance->view, + SubGhzTestStaticModel * model, + { if(event->type == InputTypeShort) { if(event->key == InputKeyLeft) { if(model->frequency > 0) model->frequency--; @@ -128,9 +130,8 @@ bool subghz_test_static_input(InputEvent* event, void* context) { } furi_record_close(RECORD_NOTIFICATION); } - - return true; - }); + }, + true); return true; } @@ -147,13 +148,14 @@ void subghz_test_static_enter(void* context) { instance->status_tx = SubGhzTestStaticStatusIDLE; with_view_model( - instance->view, (SubGhzTestStaticModel * model) { + instance->view, + SubGhzTestStaticModel * model, + { model->frequency = subghz_frequencies_433_92_testing; model->real_frequency = subghz_frequencies_testing[model->frequency]; model->button = 0; - - return true; - }); + }, + true); } void subghz_test_static_exit(void* context) { diff --git a/applications/main/subghz/views/transmitter.c b/applications/main/subghz/views/transmitter.c index 75828a13b..dc324a6a5 100644 --- a/applications/main/subghz/views/transmitter.c +++ b/applications/main/subghz/views/transmitter.c @@ -35,13 +35,15 @@ void subghz_view_transmitter_add_data_to_show( uint8_t show_button) { furi_assert(subghz_transmitter); with_view_model( - subghz_transmitter->view, (SubGhzViewTransmitterModel * model) { + subghz_transmitter->view, + SubGhzViewTransmitterModel * model, + { furi_string_set(model->key_str, key_str); furi_string_set(model->frequency_str, frequency_str); furi_string_set(model->preset_str, preset_str); model->show_button = show_button; - return true; - }); + }, + true); } static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str) { @@ -95,23 +97,27 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) { if(event->key == InputKeyBack && event->type == InputTypeShort) { with_view_model( - subghz_transmitter->view, (SubGhzViewTransmitterModel * model) { + subghz_transmitter->view, + SubGhzViewTransmitterModel * model, + { furi_string_reset(model->frequency_str); furi_string_reset(model->preset_str); furi_string_reset(model->key_str); model->show_button = 0; - return false; - }); + }, + false); return false; } with_view_model( - subghz_transmitter->view, (SubGhzViewTransmitterModel * model) { + subghz_transmitter->view, + SubGhzViewTransmitterModel * model, + { if(model->show_button) { can_be_sent = true; } - return true; - }); + }, + true); if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) { subghz_transmitter->callback( @@ -149,12 +155,14 @@ SubGhzViewTransmitter* subghz_view_transmitter_alloc() { view_set_exit_callback(subghz_transmitter->view, subghz_view_transmitter_exit); with_view_model( - subghz_transmitter->view, (SubGhzViewTransmitterModel * model) { + subghz_transmitter->view, + SubGhzViewTransmitterModel * model, + { model->frequency_str = furi_string_alloc(); model->preset_str = furi_string_alloc(); model->key_str = furi_string_alloc(); - return true; - }); + }, + true); return subghz_transmitter; } @@ -162,12 +170,14 @@ void subghz_view_transmitter_free(SubGhzViewTransmitter* subghz_transmitter) { furi_assert(subghz_transmitter); with_view_model( - subghz_transmitter->view, (SubGhzViewTransmitterModel * model) { + subghz_transmitter->view, + SubGhzViewTransmitterModel * model, + { furi_string_free(model->frequency_str); furi_string_free(model->preset_str); furi_string_free(model->key_str); - return true; - }); + }, + true); view_free(subghz_transmitter->view); free(subghz_transmitter); } diff --git a/applications/main/u2f/views/u2f_view.c b/applications/main/u2f/views/u2f_view.c index 11e2c9b04..fa3d6cc24 100644 --- a/applications/main/u2f/views/u2f_view.c +++ b/applications/main/u2f/views/u2f_view.c @@ -85,18 +85,17 @@ void u2f_view_set_ok_callback(U2fView* u2f, U2fOkCallback callback, void* contex furi_assert(u2f); furi_assert(callback); with_view_model( - u2f->view, (U2fModel * model) { + u2f->view, + U2fModel * model, + { UNUSED(model); u2f->callback = callback; u2f->context = context; - return false; - }); + }, + false); } void u2f_view_set_state(U2fView* u2f, U2fViewMsg msg) { with_view_model( - u2f->view, (U2fModel * model) { - model->display_msg = msg; - return true; - }); + u2f->view, U2fModel * model, { model->display_msg = msg; }, true); } diff --git a/applications/plugins/bt_hid_app/views/bt_hid_keyboard.c b/applications/plugins/bt_hid_app/views/bt_hid_keyboard.c index 8b9ae593a..2c65f6ab1 100644 --- a/applications/plugins/bt_hid_app/views/bt_hid_keyboard.c +++ b/applications/plugins/bt_hid_app/views/bt_hid_keyboard.c @@ -277,7 +277,9 @@ static void bt_hid_keyboard_get_select_key(BtHidKeyboardModel* model, BtHidKeybo static void bt_hid_keyboard_process(BtHidKeyboard* bt_hid_keyboard, InputEvent* event) { with_view_model( - bt_hid_keyboard->view, (BtHidKeyboardModel * model) { + bt_hid_keyboard->view, + BtHidKeyboardModel * model, + { if(event->key == InputKeyOk) { if(event->type == InputTypePress) { model->ok_pressed = true; @@ -338,8 +340,8 @@ static void bt_hid_keyboard_process(BtHidKeyboard* bt_hid_keyboard, InputEvent* bt_hid_keyboard_get_select_key(model, (BtHidKeyboardPoint){.x = 1, .y = 0}); } } - return true; - }); + }, + true); } static bool bt_hid_keyboard_input_callback(InputEvent* event, void* context) { @@ -382,8 +384,5 @@ View* bt_hid_keyboard_get_view(BtHidKeyboard* bt_hid_keyboard) { void bt_hid_keyboard_set_connected_status(BtHidKeyboard* bt_hid_keyboard, bool connected) { furi_assert(bt_hid_keyboard); with_view_model( - bt_hid_keyboard->view, (BtHidKeyboardModel * model) { - model->connected = connected; - return true; - }); + bt_hid_keyboard->view, BtHidKeyboardModel * model, { model->connected = connected; }, true); } diff --git a/applications/plugins/bt_hid_app/views/bt_hid_keynote.c b/applications/plugins/bt_hid_app/views/bt_hid_keynote.c index ea4ee16fa..db88b8000 100644 --- a/applications/plugins/bt_hid_app/views/bt_hid_keynote.c +++ b/applications/plugins/bt_hid_app/views/bt_hid_keynote.c @@ -106,7 +106,9 @@ static void bt_hid_keynote_draw_callback(Canvas* canvas, void* context) { static void bt_hid_keynote_process(BtHidKeynote* bt_hid_keynote, InputEvent* event) { with_view_model( - bt_hid_keynote->view, (BtHidKeynoteModel * model) { + bt_hid_keynote->view, + BtHidKeynoteModel * model, + { if(event->type == InputTypePress) { if(event->key == InputKeyUp) { model->up_pressed = true; @@ -153,8 +155,8 @@ static void bt_hid_keynote_process(BtHidKeynote* bt_hid_keynote, InputEvent* eve furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_AC_BACK); } } - return true; - }); + }, + true); } static bool bt_hid_keynote_input_callback(InputEvent* event, void* context) { @@ -197,8 +199,5 @@ View* bt_hid_keynote_get_view(BtHidKeynote* bt_hid_keynote) { void bt_hid_keynote_set_connected_status(BtHidKeynote* bt_hid_keynote, bool connected) { furi_assert(bt_hid_keynote); with_view_model( - bt_hid_keynote->view, (BtHidKeynoteModel * model) { - model->connected = connected; - return true; - }); + bt_hid_keynote->view, BtHidKeynoteModel * model, { model->connected = connected; }, true); } diff --git a/applications/plugins/bt_hid_app/views/bt_hid_media.c b/applications/plugins/bt_hid_app/views/bt_hid_media.c index 258ea0a40..181cd347b 100644 --- a/applications/plugins/bt_hid_app/views/bt_hid_media.c +++ b/applications/plugins/bt_hid_app/views/bt_hid_media.c @@ -107,7 +107,9 @@ static void bt_hid_media_draw_callback(Canvas* canvas, void* context) { static void bt_hid_media_process_press(BtHidMedia* bt_hid_media, InputEvent* event) { with_view_model( - bt_hid_media->view, (BtHidMediaModel * model) { + bt_hid_media->view, + BtHidMediaModel * model, + { if(event->key == InputKeyUp) { model->up_pressed = true; furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_VOLUME_INCREMENT); @@ -124,13 +126,15 @@ static void bt_hid_media_process_press(BtHidMedia* bt_hid_media, InputEvent* eve model->ok_pressed = true; furi_hal_bt_hid_consumer_key_press(HID_CONSUMER_PLAY_PAUSE); } - return true; - }); + }, + true); } static void bt_hid_media_process_release(BtHidMedia* bt_hid_media, InputEvent* event) { with_view_model( - bt_hid_media->view, (BtHidMediaModel * model) { + bt_hid_media->view, + BtHidMediaModel * model, + { if(event->key == InputKeyUp) { model->up_pressed = false; furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_VOLUME_INCREMENT); @@ -147,8 +151,8 @@ static void bt_hid_media_process_release(BtHidMedia* bt_hid_media, InputEvent* e model->ok_pressed = false; furi_hal_bt_hid_consumer_key_release(HID_CONSUMER_PLAY_PAUSE); } - return true; - }); + }, + true); } static bool bt_hid_media_input_callback(InputEvent* event, void* context) { @@ -196,8 +200,5 @@ View* bt_hid_media_get_view(BtHidMedia* bt_hid_media) { void bt_hid_media_set_connected_status(BtHidMedia* bt_hid_media, bool connected) { furi_assert(bt_hid_media); with_view_model( - bt_hid_media->view, (BtHidMediaModel * model) { - model->connected = connected; - return true; - }); + bt_hid_media->view, BtHidMediaModel * model, { model->connected = connected; }, true); } diff --git a/applications/plugins/bt_hid_app/views/bt_hid_mouse.c b/applications/plugins/bt_hid_app/views/bt_hid_mouse.c index 395cb52c9..098adb732 100644 --- a/applications/plugins/bt_hid_app/views/bt_hid_mouse.c +++ b/applications/plugins/bt_hid_app/views/bt_hid_mouse.c @@ -103,7 +103,9 @@ static void bt_hid_mouse_draw_callback(Canvas* canvas, void* context) { static void bt_hid_mouse_process(BtHidMouse* bt_hid_mouse, InputEvent* event) { with_view_model( - bt_hid_mouse->view, (BtHidMouseModel * model) { + bt_hid_mouse->view, + BtHidMouseModel * model, + { if(event->key == InputKeyBack) { if(event->type == InputTypeShort) { furi_hal_bt_hid_mouse_press(HID_MOUSE_BTN_RIGHT); @@ -167,8 +169,8 @@ static void bt_hid_mouse_process(BtHidMouse* bt_hid_mouse, InputEvent* event) { model->up_pressed = false; } } - return true; - }); + }, + true); } static bool bt_hid_mouse_input_callback(InputEvent* event, void* context) { @@ -211,8 +213,5 @@ View* bt_hid_mouse_get_view(BtHidMouse* bt_hid_mouse) { void bt_hid_mouse_set_connected_status(BtHidMouse* bt_hid_mouse, bool connected) { furi_assert(bt_hid_mouse); with_view_model( - bt_hid_mouse->view, (BtHidMouseModel * model) { - model->connected = connected; - return true; - }); + bt_hid_mouse->view, BtHidMouseModel * model, { model->connected = connected; }, true); } diff --git a/applications/plugins/signal_generator/views/signal_gen_pwm.c b/applications/plugins/signal_generator/views/signal_gen_pwm.c index 4afed01a6..6d1a3c1ba 100644 --- a/applications/plugins/signal_generator/views/signal_gen_pwm.c +++ b/applications/plugins/signal_generator/views/signal_gen_pwm.c @@ -44,12 +44,14 @@ static void pwm_set_config(SignalGenPwm* pwm) { uint8_t duty; with_view_model( - pwm->view, (SignalGenPwmViewModel * model) { + pwm->view, + SignalGenPwmViewModel * model, + { channel = model->channel_id; freq = model->freq; duty = model->duty; - return false; - }); + }, + false); furi_assert(pwm->callback); pwm->callback(channel, freq, duty, pwm->context); @@ -188,7 +190,9 @@ static bool signal_gen_pwm_input_callback(InputEvent* event, void* context) { bool need_update = false; with_view_model( - pwm->view, (SignalGenPwmViewModel * model) { + pwm->view, + SignalGenPwmViewModel * model, + { if(model->edit_mode == false) { if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) { if(event->key == InputKeyUp) { @@ -238,8 +242,8 @@ static bool signal_gen_pwm_input_callback(InputEvent* event, void* context) { } } } - return true; - }); + }, + true); if(need_update) { pwm_set_config(pwm); @@ -279,22 +283,26 @@ void signal_gen_pwm_set_callback( furi_assert(callback); with_view_model( - pwm->view, (SignalGenPwmViewModel * model) { + pwm->view, + SignalGenPwmViewModel * model, + { UNUSED(model); pwm->callback = callback; pwm->context = context; - return false; - }); + }, + false); } void signal_gen_pwm_set_params(SignalGenPwm* pwm, uint8_t channel_id, uint32_t freq, uint8_t duty) { with_view_model( - pwm->view, (SignalGenPwmViewModel * model) { + pwm->view, + SignalGenPwmViewModel * model, + { model->channel_id = channel_id; model->freq = freq; model->duty = duty; - return true; - }); + }, + true); furi_assert(pwm->callback); pwm->callback(channel_id, freq, duty, pwm->context); diff --git a/applications/plugins/subbrute/views/subbrute_attack_view.c b/applications/plugins/subbrute/views/subbrute_attack_view.c index 63328d771..e783d9f4c 100644 --- a/applications/plugins/subbrute/views/subbrute_attack_view.c +++ b/applications/plugins/subbrute/views/subbrute_attack_view.c @@ -47,21 +47,23 @@ bool subbrute_attack_view_input(InputEvent* event, void* context) { if(event->key == InputKeyBack && event->type == InputTypeShort) { instance->callback(SubBruteCustomEventTypeBackPressed, instance->context); with_view_model( - instance->view, (SubBruteAttackViewModel * model) { + instance->view, + SubBruteAttackViewModel * model, + { model->is_attacking = false; model->is_continuous_worker = false; - return true; - }); + }, + true); return true; } bool is_attacking = false; with_view_model( - instance->view, (SubBruteAttackViewModel * model) { - is_attacking = model->is_attacking; - return false; - }); + instance->view, + SubBruteAttackViewModel * model, + { is_attacking = model->is_attacking; }, + false); // if(!is_attacking) { // instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context); @@ -75,13 +77,15 @@ bool subbrute_attack_view_input(InputEvent* event, void* context) { FURI_LOG_D(TAG, "InputKey: %d OK", event->key); #endif with_view_model( - instance->view, (SubBruteAttackViewModel * model) { + instance->view, + SubBruteAttackViewModel * model, + { model->is_attacking = true; model->is_continuous_worker = false; icon_animation_stop(model->icon); icon_animation_start(model->icon); - return true; - }); + }, + true); instance->callback(SubBruteCustomEventTypeTransmitStarted, instance->context); /*if(event->type == InputTypeRepeat && event->key == InputKeyOk) { #ifdef FURI_DEBUG @@ -152,13 +156,15 @@ bool subbrute_attack_view_input(InputEvent* event, void* context) { if((event->type == InputTypeShort || event->type == InputTypeRepeat) && (event->key == InputKeyOk || event->key == InputKeyBack)) { with_view_model( - instance->view, (SubBruteAttackViewModel * model) { + instance->view, + SubBruteAttackViewModel * model, + { model->is_attacking = false; model->is_continuous_worker = false; icon_animation_stop(model->icon); icon_animation_start(model->icon); - return true; - }); + }, + true); instance->callback(SubBruteCustomEventTypeTransmitNotStarted, instance->context); } } @@ -174,11 +180,13 @@ SubBruteAttackView* subbrute_attack_view_alloc() { view_set_context(instance->view, instance); with_view_model( - instance->view, (SubBruteAttackViewModel * model) { + instance->view, + SubBruteAttackViewModel * model, + { model->icon = icon_animation_alloc(&A_Sub1ghz_14); view_tie_icon_animation(instance->view, model->icon); - return false; - }); + }, + false); view_set_draw_callback(instance->view, (ViewDrawCallback)subbrute_attack_view_draw); view_set_input_callback(instance->view, subbrute_attack_view_input); @@ -204,10 +212,10 @@ void subbrute_attack_view_free(SubBruteAttackView* instance) { #endif with_view_model( - instance->view, (SubBruteAttackViewModel * model) { - icon_animation_free(model->icon); - return false; - }); + instance->view, + SubBruteAttackViewModel * model, + { icon_animation_free(model->icon); }, + false); view_free(instance->view); free(instance); @@ -224,19 +232,19 @@ void subbrute_attack_view_set_current_step(SubBruteAttackView* instance, uint64_ //FURI_LOG_D(TAG, "Set step: %d", current_step); #endif with_view_model( - instance->view, (SubBruteAttackViewModel * model) { - model->current_step = current_step; - return true; - }); + instance->view, + SubBruteAttackViewModel * model, + { model->current_step = current_step; }, + true); } void subbrute_attack_view_set_worker_type(SubBruteAttackView* instance, bool is_continuous_worker) { furi_assert(instance); with_view_model( - instance->view, (SubBruteAttackViewModel * model) { - model->is_continuous_worker = is_continuous_worker; - return true; - }); + instance->view, + SubBruteAttackViewModel * model, + { model->is_continuous_worker = is_continuous_worker; }, + true); } // We need to call init every time, because not every time we calls enter @@ -256,7 +264,9 @@ void subbrute_attack_view_init_values( current_step); #endif with_view_model( - instance->view, (SubBruteAttackViewModel * model) { + instance->view, + SubBruteAttackViewModel * model, + { model->max_value = max_value; model->index = index; model->current_step = current_step; @@ -266,8 +276,8 @@ void subbrute_attack_view_init_values( } else { icon_animation_stop(model->icon); } - return true; - }); + }, + true); } void subbrute_attack_view_exit(void* context) { @@ -277,10 +287,10 @@ void subbrute_attack_view_exit(void* context) { FURI_LOG_D(TAG, "subbrute_attack_view_exit"); #endif with_view_model( - instance->view, (SubBruteAttackViewModel * model) { - icon_animation_stop(model->icon); - return false; - }); + instance->view, + SubBruteAttackViewModel * model, + { icon_animation_stop(model->icon); }, + false); } void elements_button_top_left(Canvas* canvas, const char* str) { diff --git a/applications/plugins/subbrute/views/subbrute_main_view.c b/applications/plugins/subbrute/views/subbrute_main_view.c index 23095e17f..2010e9ae2 100644 --- a/applications/plugins/subbrute/views/subbrute_main_view.c +++ b/applications/plugins/subbrute/views/subbrute_main_view.c @@ -173,17 +173,19 @@ bool subbrute_main_view_input(InputEvent* event, void* context) { uint8_t index = 0; bool is_select_byte = false; with_view_model( - instance->view, (SubBruteMainViewModel * model) { - is_select_byte = model->is_select_byte; - return false; - }); + instance->view, + SubBruteMainViewModel * model, + { is_select_byte = model->is_select_byte; }, + false); bool consumed = false; if(!is_select_byte) { if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) { + bool ret = false; with_view_model( - instance->view, (SubBruteMainViewModel * model) { - bool ret = false; + instance->view, + SubBruteMainViewModel * model, + { uint8_t items_on_screen = 3; if(event->key == InputKeyUp) { if(model->index == min_value) { @@ -219,8 +221,8 @@ bool subbrute_main_view_input(InputEvent* event, void* context) { } } index = model->index; - return ret; - }); + }, + ret); } #ifdef FURI_DEBUG @@ -243,7 +245,9 @@ bool subbrute_main_view_input(InputEvent* event, void* context) { } else { if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) { with_view_model( - instance->view, (SubBruteMainViewModel * model) { + instance->view, + SubBruteMainViewModel * model, + { if(event->key == InputKeyLeft) { if(model->index > 0) { model->index--; @@ -255,8 +259,8 @@ bool subbrute_main_view_input(InputEvent* event, void* context) { } index = model->index; - return true; - }); + }, + true); } #ifdef FURI_DEBUG @@ -304,13 +308,15 @@ SubBruteMainView* subbrute_main_view_alloc() { view_set_exit_callback(instance->view, subbrute_main_view_exit); with_view_model( - instance->view, (SubBruteMainViewModel * model) { + instance->view, + SubBruteMainViewModel * model, + { model->index = 0; model->window_position = 0; model->key_field = NULL; model->is_select_byte = false; - return true; - }); + }, + true); return instance; } @@ -338,7 +344,9 @@ void subbrute_main_view_set_index( FURI_LOG_I(TAG, "Set index: %d", idx); #endif with_view_model( - instance->view, (SubBruteMainViewModel * model) { + instance->view, + SubBruteMainViewModel * model, + { model->is_select_byte = is_select_byte; model->key_field = key_field; model->index = idx; @@ -359,8 +367,8 @@ void subbrute_main_view_set_index( } } } - return true; - }); + }, + true); } SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance) { @@ -368,10 +376,7 @@ SubBruteAttacks subbrute_main_view_get_index(SubBruteMainView* instance) { uint8_t idx = 0; with_view_model( - instance->view, (SubBruteMainViewModel * model) { - idx = model->index; - return false; - }); + instance->view, SubBruteMainViewModel * model, { idx = model->index; }, false); #ifdef FURI_DEBUG FURI_LOG_D(TAG, "Get index: %d", idx); diff --git a/applications/plugins/usbkeyboard/application.fam b/applications/plugins/usbkeyboard/application.fam new file mode 100644 index 000000000..b5ac0f74f --- /dev/null +++ b/applications/plugins/usbkeyboard/application.fam @@ -0,0 +1,14 @@ +App( + appid="USB_Keyboard", + name="USB Keyboard & Mouse", + apptype=FlipperAppType.EXTERNAL, + entry_point="usb_hid_app", + stack_size=1 * 1024, + cdefines=["APP_USB_KEYBOARD"], + requires=[ + "gui", + ], + order=60, + fap_icon="usb_keyboard_10px.png", + fap_category="Misc", +) diff --git a/applications/plugins/usbkeyboard/usb_hid.c b/applications/plugins/usbkeyboard/usb_hid.c new file mode 100644 index 000000000..c2344565b --- /dev/null +++ b/applications/plugins/usbkeyboard/usb_hid.c @@ -0,0 +1,171 @@ +#include "usb_hid.h" +#include +#include +#include + +#define TAG "UsbHidApp" + +enum UsbDebugSubmenuIndex { + UsbHidSubmenuIndexDirpad, + UsbHidSubmenuIndexKeyboard, + UsbHidSubmenuIndexMedia, + UsbHidSubmenuIndexMouse, +}; + +void usb_hid_submenu_callback(void* context, uint32_t index) { + furi_assert(context); + UsbHid* app = context; + if(index == UsbHidSubmenuIndexDirpad) { + app->view_id = UsbHidViewDirpad; + view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewDirpad); + } else if(index == UsbHidSubmenuIndexKeyboard) { + app->view_id = UsbHidViewKeyboard; + view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewKeyboard); + } else if(index == UsbHidSubmenuIndexMedia) { + app->view_id = UsbHidViewMedia; + view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewMedia); + } else if(index == UsbHidSubmenuIndexMouse) { + app->view_id = UsbHidViewMouse; + view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewMouse); + } +} + +void usb_hid_dialog_callback(DialogExResult result, void* context) { + furi_assert(context); + UsbHid* app = context; + if(result == DialogExResultLeft) { + view_dispatcher_stop(app->view_dispatcher); + } else if(result == DialogExResultRight) { + view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); // Show last view + } else if(result == DialogExResultCenter) { + view_dispatcher_switch_to_view(app->view_dispatcher, UsbHidViewSubmenu); + } +} + +uint32_t usb_hid_exit_confirm_view(void* context) { + UNUSED(context); + return UsbHidViewExitConfirm; +} + +uint32_t usb_hid_exit(void* context) { + UNUSED(context); + return VIEW_NONE; +} + +UsbHid* usb_hid_app_alloc() { + UsbHid* app = malloc(sizeof(UsbHid)); + + // Gui + app->gui = furi_record_open(RECORD_GUI); + + // 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_add_item( + app->submenu, "Dirpad", UsbHidSubmenuIndexDirpad, usb_hid_submenu_callback, app); + submenu_add_item( + app->submenu, "Keyboard", UsbHidSubmenuIndexKeyboard, usb_hid_submenu_callback, app); + submenu_add_item(app->submenu, "Media", UsbHidSubmenuIndexMedia, usb_hid_submenu_callback, app); + submenu_add_item(app->submenu, "Mouse", UsbHidSubmenuIndexMouse, usb_hid_submenu_callback, app); + view_set_previous_callback(submenu_get_view(app->submenu), usb_hid_exit); + view_dispatcher_add_view( + app->view_dispatcher, UsbHidViewSubmenu, submenu_get_view(app->submenu)); + + // Dialog view + app->dialog = dialog_ex_alloc(); + dialog_ex_set_result_callback(app->dialog, usb_hid_dialog_callback); + dialog_ex_set_context(app->dialog, app); + dialog_ex_set_left_button_text(app->dialog, "Exit"); + dialog_ex_set_right_button_text(app->dialog, "Stay"); + dialog_ex_set_center_button_text(app->dialog, "Menu"); + dialog_ex_set_header(app->dialog, "Close Current App?", 16, 12, AlignLeft, AlignTop); + view_dispatcher_add_view( + app->view_dispatcher, UsbHidViewExitConfirm, dialog_ex_get_view(app->dialog)); + + // Dirpad view + app->usb_hid_dirpad = usb_hid_dirpad_alloc(); + view_set_previous_callback( + usb_hid_dirpad_get_view(app->usb_hid_dirpad), usb_hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, UsbHidViewDirpad, usb_hid_dirpad_get_view(app->usb_hid_dirpad)); + + // Keyboard view + app->usb_hid_keyboard = usb_hid_keyboard_alloc(); + view_set_previous_callback( + usb_hid_keyboard_get_view(app->usb_hid_keyboard), usb_hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, UsbHidViewKeyboard, usb_hid_keyboard_get_view(app->usb_hid_keyboard)); + + // Media view + app->usb_hid_media = usb_hid_media_alloc(); + view_set_previous_callback(usb_hid_media_get_view(app->usb_hid_media), usb_hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, UsbHidViewMedia, usb_hid_media_get_view(app->usb_hid_media)); + + // Mouse view + app->usb_hid_mouse = usb_hid_mouse_alloc(); + view_set_previous_callback(usb_hid_mouse_get_view(app->usb_hid_mouse), usb_hid_exit_confirm_view); + view_dispatcher_add_view( + app->view_dispatcher, UsbHidViewMouse, usb_hid_mouse_get_view(app->usb_hid_mouse)); + + // TODO switch to menu after Media is done + app->view_id = UsbHidViewSubmenu; + view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); + + return app; +} + +void usb_hid_app_free(UsbHid* app) { + furi_assert(app); + + // Reset notification + notification_internal_message(app->notifications, &sequence_reset_blue); + + // Free views + view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewSubmenu); + submenu_free(app->submenu); + view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewExitConfirm); + dialog_ex_free(app->dialog); + view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewDirpad); + usb_hid_dirpad_free(app->usb_hid_dirpad); + view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewKeyboard); + usb_hid_keyboard_free(app->usb_hid_keyboard); + view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewMedia); + usb_hid_media_free(app->usb_hid_media); + view_dispatcher_remove_view(app->view_dispatcher, UsbHidViewMouse); + usb_hid_mouse_free(app->usb_hid_mouse); + view_dispatcher_free(app->view_dispatcher); + // Close records + furi_record_close(RECORD_GUI); + app->gui = NULL; + furi_record_close(RECORD_NOTIFICATION); + app->notifications = NULL; + + // Free rest + free(app); +} + +int32_t usb_hid_app(void* p) { + UNUSED(p); + // Switch profile to Hid + UsbHid* app = usb_hid_app_alloc(); + + FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); + furi_hal_usb_unlock(); + furi_check(furi_hal_usb_set_config(&usb_hid, NULL) == true); + + view_dispatcher_run(app->view_dispatcher); + + // Change back profile + furi_hal_usb_set_config(usb_mode_prev, NULL); + usb_hid_app_free(app); + + return 0; +} diff --git a/applications/plugins/usbkeyboard/usb_hid.h b/applications/plugins/usbkeyboard/usb_hid.h new file mode 100644 index 000000000..90c214c48 --- /dev/null +++ b/applications/plugins/usbkeyboard/usb_hid.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include "views/usb_hid_dirpad.h" +#include "views/usb_hid_keyboard.h" +#include "views/usb_hid_media.h" +#include "views/usb_hid_mouse.h" + +typedef struct { + Gui* gui; + NotificationApp* notifications; + ViewDispatcher* view_dispatcher; + Submenu* submenu; + DialogEx* dialog; + UsbHidDirpad* usb_hid_dirpad; + UsbHidKeyboard* usb_hid_keyboard; + UsbHidMedia* usb_hid_media; + UsbHidMouse* usb_hid_mouse; + uint32_t view_id; +} UsbHid; + +typedef enum { + UsbHidViewSubmenu, + UsbHidViewDirpad, + UsbHidViewKeyboard, + UsbHidViewMedia, + UsbHidViewMouse, + UsbHidViewExitConfirm, +} UsbHidView; diff --git a/applications/plugins/usbkeyboard/usb_keyboard_10px.png b/applications/plugins/usbkeyboard/usb_keyboard_10px.png new file mode 100644 index 000000000..7649138eb Binary files /dev/null and b/applications/plugins/usbkeyboard/usb_keyboard_10px.png differ diff --git a/applications/plugins/usbkeyboard/views/usb_hid_dirpad.c b/applications/plugins/usbkeyboard/views/usb_hid_dirpad.c new file mode 100644 index 000000000..f17dc1a00 --- /dev/null +++ b/applications/plugins/usbkeyboard/views/usb_hid_dirpad.c @@ -0,0 +1,196 @@ +#include "usb_hid_dirpad.h" +#include +#include +#include + +struct UsbHidDirpad { + View* view; +}; + +typedef struct { + bool left_pressed; + bool up_pressed; + bool right_pressed; + bool down_pressed; + bool ok_pressed; + bool back_pressed; + bool connected; +} UsbHidDirpadModel; + +static void usb_hid_dirpad_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 usb_hid_dirpad_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + UsbHidDirpadModel* model = context; + + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Dirpad"); + + 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); + } + usb_hid_dirpad_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); + } + usb_hid_dirpad_draw_arrow(canvas, 30, 55, CanvasDirectionTopToBottom); + canvas_set_color(canvas, ColorBlack); + + // Left + canvas_draw_icon(canvas, 0, 45, &I_Button_18x18); + if(model->left_pressed) { + elements_slightly_rounded_box(canvas, 3, 47, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + usb_hid_dirpad_draw_arrow(canvas, 7, 53, CanvasDirectionRightToLeft); + canvas_set_color(canvas, ColorBlack); + + // Right + canvas_draw_icon(canvas, 42, 45, &I_Button_18x18); + if(model->right_pressed) { + elements_slightly_rounded_box(canvas, 45, 47, 13, 13); + canvas_set_color(canvas, ColorWhite); + } + usb_hid_dirpad_draw_arrow(canvas, 53, 53, 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 usb_hid_dirpad_process(UsbHidDirpad* usb_hid_dirpad, InputEvent* event) { + with_view_model( + usb_hid_dirpad->view, + UsbHidDirpadModel * model, + { + if(event->type == InputTypePress) { + if(event->key == InputKeyUp) { + model->up_pressed = true; + furi_hal_hid_kb_press(HID_KEYBOARD_UP_ARROW); + } else if(event->key == InputKeyDown) { + model->down_pressed = true; + furi_hal_hid_kb_press(HID_KEYBOARD_DOWN_ARROW); + } else if(event->key == InputKeyLeft) { + model->left_pressed = true; + furi_hal_hid_kb_press(HID_KEYBOARD_LEFT_ARROW); + } else if(event->key == InputKeyRight) { + model->right_pressed = true; + furi_hal_hid_kb_press(HID_KEYBOARD_RIGHT_ARROW); + } else if(event->key == InputKeyOk) { + model->ok_pressed = true; + furi_hal_hid_kb_press(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; + furi_hal_hid_kb_release(HID_KEYBOARD_UP_ARROW); + } else if(event->key == InputKeyDown) { + model->down_pressed = false; + furi_hal_hid_kb_release(HID_KEYBOARD_DOWN_ARROW); + } else if(event->key == InputKeyLeft) { + model->left_pressed = false; + furi_hal_hid_kb_release(HID_KEYBOARD_LEFT_ARROW); + } else if(event->key == InputKeyRight) { + model->right_pressed = false; + furi_hal_hid_kb_release(HID_KEYBOARD_RIGHT_ARROW); + } else if(event->key == InputKeyOk) { + model->ok_pressed = false; + furi_hal_hid_kb_release(HID_KEYBOARD_SPACEBAR); + } else if(event->key == InputKeyBack) { + model->back_pressed = false; + } + } else if(event->type == InputTypeShort) { + if(event->key == InputKeyBack) { + furi_hal_hid_kb_press(HID_KEYBOARD_DELETE); + furi_hal_hid_kb_release(HID_KEYBOARD_DELETE); + furi_hal_hid_consumer_key_press(HID_CONSUMER_AC_BACK); + furi_hal_hid_consumer_key_release(HID_CONSUMER_AC_BACK); + } + } + }, + true); +} + +static bool usb_hid_dirpad_input_callback(InputEvent* event, void* context) { + furi_assert(context); + UsbHidDirpad* usb_hid_dirpad = context; + bool consumed = false; + + if(event->type == InputTypeLong && event->key == InputKeyBack) { + furi_hal_hid_kb_release_all(); + } else { + usb_hid_dirpad_process(usb_hid_dirpad, event); + consumed = true; + } + + return consumed; +} + +UsbHidDirpad* usb_hid_dirpad_alloc() { + UsbHidDirpad* usb_hid_dirpad = malloc(sizeof(UsbHidDirpad)); + usb_hid_dirpad->view = view_alloc(); + view_set_context(usb_hid_dirpad->view, usb_hid_dirpad); + view_allocate_model(usb_hid_dirpad->view, ViewModelTypeLocking, sizeof(UsbHidDirpadModel)); + view_set_draw_callback(usb_hid_dirpad->view, usb_hid_dirpad_draw_callback); + view_set_input_callback(usb_hid_dirpad->view, usb_hid_dirpad_input_callback); + + return usb_hid_dirpad; +} + +void usb_hid_dirpad_free(UsbHidDirpad* usb_hid_dirpad) { + furi_assert(usb_hid_dirpad); + view_free(usb_hid_dirpad->view); + free(usb_hid_dirpad); +} + +View* usb_hid_dirpad_get_view(UsbHidDirpad* usb_hid_dirpad) { + furi_assert(usb_hid_dirpad); + return usb_hid_dirpad->view; +} + +void usb_hid_dirpad_set_connected_status(UsbHidDirpad* usb_hid_dirpad, bool connected) { + furi_assert(usb_hid_dirpad); + with_view_model( + usb_hid_dirpad->view, UsbHidDirpadModel * model, { model->connected = connected; }, true); +} diff --git a/applications/plugins/usbkeyboard/views/usb_hid_dirpad.h b/applications/plugins/usbkeyboard/views/usb_hid_dirpad.h new file mode 100644 index 000000000..305e051b4 --- /dev/null +++ b/applications/plugins/usbkeyboard/views/usb_hid_dirpad.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +typedef struct UsbHidDirpad UsbHidDirpad; + +UsbHidDirpad* usb_hid_dirpad_alloc(); + +void usb_hid_dirpad_free(UsbHidDirpad* usb_hid_dirpad); + +View* usb_hid_dirpad_get_view(UsbHidDirpad* usb_hid_dirpad); + +void usb_hid_dirpad_set_connected_status(UsbHidDirpad* usb_hid_dirpad, bool connected); diff --git a/applications/plugins/usbkeyboard/views/usb_hid_keyboard.c b/applications/plugins/usbkeyboard/views/usb_hid_keyboard.c new file mode 100644 index 000000000..687189e7d --- /dev/null +++ b/applications/plugins/usbkeyboard/views/usb_hid_keyboard.c @@ -0,0 +1,371 @@ +#include "usb_hid_keyboard.h" +#include +#include +#include +#include + +struct UsbHidKeyboard { + View* view; +}; + +typedef struct { + bool shift; + bool alt; + bool ctrl; + bool gui; + uint8_t x; + uint8_t y; + uint8_t last_key_code; + uint16_t modifier_code; + bool ok_pressed; + bool back_pressed; + bool connected; + char key_string[5]; +} UsbHidKeyboardModel; + +typedef struct { + uint8_t width; + char* key; + const Icon* icon; + char* shift_key; + uint8_t value; +} UsbHidKeyboardKey; + +typedef struct { + int8_t x; + int8_t y; +} UsbHidKeyboardPoint; + +// 4 BY 12 +#define MARGIN_TOP 0 +#define MARGIN_LEFT 4 +#define KEY_WIDTH 9 +#define KEY_HEIGHT 12 +#define KEY_PADDING 1 +#define ROW_COUNT 6 +#define COLUMN_COUNT 12 + +// 0 width items are not drawn, but there value is used +const UsbHidKeyboardKey usb_hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { + { + {.width = 1, .icon = NULL, .key = "1", .shift_key = "!", .value = HID_KEYBOARD_1}, + {.width = 1, .icon = NULL, .key = "2", .shift_key = "@", .value = HID_KEYBOARD_2}, + {.width = 1, .icon = NULL, .key = "3", .shift_key = "#", .value = HID_KEYBOARD_3}, + {.width = 1, .icon = NULL, .key = "4", .shift_key = "$", .value = HID_KEYBOARD_4}, + {.width = 1, .icon = NULL, .key = "5", .shift_key = "%", .value = HID_KEYBOARD_5}, + {.width = 1, .icon = NULL, .key = "6", .shift_key = "^", .value = HID_KEYBOARD_6}, + {.width = 1, .icon = NULL, .key = "7", .shift_key = "&", .value = HID_KEYBOARD_7}, + {.width = 1, .icon = NULL, .key = "8", .shift_key = "*", .value = HID_KEYBOARD_8}, + {.width = 1, .icon = NULL, .key = "9", .shift_key = "(", .value = HID_KEYBOARD_9}, + {.width = 1, .icon = NULL, .key = "0", .shift_key = ")", .value = HID_KEYBOARD_0}, + {.width = 2, .icon = &I_Pin_arrow_left_9x7, .value = HID_KEYBOARD_DELETE}, + {.width = 0, .value = HID_KEYBOARD_DELETE}, + }, + { + {.width = 1, .icon = NULL, .key = "q", .shift_key = "Q", .value = HID_KEYBOARD_Q}, + {.width = 1, .icon = NULL, .key = "w", .shift_key = "W", .value = HID_KEYBOARD_W}, + {.width = 1, .icon = NULL, .key = "e", .shift_key = "E", .value = HID_KEYBOARD_E}, + {.width = 1, .icon = NULL, .key = "r", .shift_key = "R", .value = HID_KEYBOARD_R}, + {.width = 1, .icon = NULL, .key = "t", .shift_key = "T", .value = HID_KEYBOARD_T}, + {.width = 1, .icon = NULL, .key = "y", .shift_key = "Y", .value = HID_KEYBOARD_Y}, + {.width = 1, .icon = NULL, .key = "u", .shift_key = "U", .value = HID_KEYBOARD_U}, + {.width = 1, .icon = NULL, .key = "i", .shift_key = "I", .value = HID_KEYBOARD_I}, + {.width = 1, .icon = NULL, .key = "o", .shift_key = "O", .value = HID_KEYBOARD_O}, + {.width = 1, .icon = NULL, .key = "p", .shift_key = "P", .value = HID_KEYBOARD_P}, + {.width = 1, .icon = NULL, .key = "[", .shift_key = "{", .value = HID_KEYBOARD_OPEN_BRACKET}, + {.width = 1, + .icon = NULL, + .key = "]", + .shift_key = "}", + .value = HID_KEYBOARD_CLOSE_BRACKET}, + }, + { + {.width = 1, .icon = NULL, .key = "a", .shift_key = "A", .value = HID_KEYBOARD_A}, + {.width = 1, .icon = NULL, .key = "s", .shift_key = "S", .value = HID_KEYBOARD_S}, + {.width = 1, .icon = NULL, .key = "d", .shift_key = "D", .value = HID_KEYBOARD_D}, + {.width = 1, .icon = NULL, .key = "f", .shift_key = "F", .value = HID_KEYBOARD_F}, + {.width = 1, .icon = NULL, .key = "g", .shift_key = "G", .value = HID_KEYBOARD_G}, + {.width = 1, .icon = NULL, .key = "h", .shift_key = "H", .value = HID_KEYBOARD_H}, + {.width = 1, .icon = NULL, .key = "j", .shift_key = "J", .value = HID_KEYBOARD_J}, + {.width = 1, .icon = NULL, .key = "k", .shift_key = "K", .value = HID_KEYBOARD_K}, + {.width = 1, .icon = NULL, .key = "l", .shift_key = "L", .value = HID_KEYBOARD_L}, + {.width = 1, .icon = NULL, .key = ";", .shift_key = ":", .value = HID_KEYBOARD_SEMICOLON}, + {.width = 2, .icon = &I_Pin_arrow_right_9x7, .value = HID_KEYBOARD_RETURN}, + {.width = 0, .value = HID_KEYBOARD_RETURN}, + }, + { + {.width = 1, .icon = NULL, .key = "z", .shift_key = "Z", .value = HID_KEYBOARD_Z}, + {.width = 1, .icon = NULL, .key = "x", .shift_key = "X", .value = HID_KEYBOARD_X}, + {.width = 1, .icon = NULL, .key = "c", .shift_key = "C", .value = HID_KEYBOARD_C}, + {.width = 1, .icon = NULL, .key = "v", .shift_key = "V", .value = HID_KEYBOARD_V}, + {.width = 1, .icon = NULL, .key = "b", .shift_key = "B", .value = HID_KEYBOARD_B}, + {.width = 1, .icon = NULL, .key = "n", .shift_key = "N", .value = HID_KEYBOARD_N}, + {.width = 1, .icon = NULL, .key = "m", .shift_key = "M", .value = HID_KEYBOARD_M}, + {.width = 1, .icon = NULL, .key = "/", .shift_key = "?", .value = HID_KEYBOARD_SLASH}, + {.width = 1, .icon = NULL, .key = "\\", .shift_key = "|", .value = HID_KEYBOARD_BACKSLASH}, + {.width = 1, .icon = NULL, .key = "`", .shift_key = "~", .value = HID_KEYBOARD_GRAVE_ACCENT}, + {.width = 1, .icon = &I_ButtonUp_7x4, .value = HID_KEYBOARD_UP_ARROW}, + {.width = 1, .icon = NULL, .key = "-", .shift_key = "_", .value = HID_KEYBOARD_MINUS}, + }, + { + {.width = 1, .icon = &I_Pin_arrow_up_7x9, .value = HID_KEYBOARD_L_SHIFT}, + {.width = 1, .icon = NULL, .key = ",", .shift_key = "<", .value = HID_KEYPAD_COMMA}, + {.width = 1, .icon = NULL, .key = ".", .shift_key = ">", .value = HID_KEYBOARD_DOT}, + {.width = 4, .icon = NULL, .key = " ", .value = HID_KEYBOARD_SPACEBAR}, + {.width = 0, .value = HID_KEYBOARD_SPACEBAR}, + {.width = 0, .value = HID_KEYBOARD_SPACEBAR}, + {.width = 0, .value = HID_KEYBOARD_SPACEBAR}, + {.width = 1, .icon = NULL, .key = "'", .shift_key = "\"", .value = HID_KEYBOARD_APOSTROPHE}, + {.width = 1, .icon = NULL, .key = "=", .shift_key = "+", .value = HID_KEYBOARD_EQUAL_SIGN}, + {.width = 1, .icon = &I_ButtonLeft_4x7, .value = HID_KEYBOARD_LEFT_ARROW}, + {.width = 1, .icon = &I_ButtonDown_7x4, .value = HID_KEYBOARD_DOWN_ARROW}, + {.width = 1, .icon = &I_ButtonRight_4x7, .value = HID_KEYBOARD_RIGHT_ARROW}, + }, + { + {.width = 3, .icon = NULL, .key = "Ctrl", .value = HID_KEYBOARD_L_CTRL}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_CTRL}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_CTRL}, + {.width = 3, .icon = NULL, .key = "Alt", .value = HID_KEYBOARD_L_ALT}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_ALT}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_ALT}, + {.width = 3, .icon = NULL, .key = "Cmd", .value = HID_KEYBOARD_L_GUI}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_GUI}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_L_GUI}, + {.width = 3, .icon = NULL, .key = "Tab", .value = HID_KEYBOARD_TAB}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_TAB}, + {.width = 0, .icon = NULL, .value = HID_KEYBOARD_TAB}, + }, +}; + +static void usb_hid_keyboard_to_upper(char* str) { + while(*str) { + *str = toupper((unsigned char)*str); + str++; + } +} + +static void usb_hid_keyboard_draw_key( + Canvas* canvas, + UsbHidKeyboardModel* model, + uint8_t x, + uint8_t y, + UsbHidKeyboardKey key, + bool selected) { + if(!key.width) return; + + canvas_set_color(canvas, ColorBlack); + uint8_t keyWidth = KEY_WIDTH * key.width + KEY_PADDING * (key.width - 1); + if(selected) { + // Draw a filled box + elements_slightly_rounded_box( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), + keyWidth, + KEY_HEIGHT); + canvas_set_color(canvas, ColorWhite); + } else { + // Draw a framed box + elements_slightly_rounded_frame( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING), + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING), + keyWidth, + KEY_HEIGHT); + } + if(key.icon != NULL) { + // Draw the icon centered on the button + canvas_draw_icon( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 - key.icon->width / 2, + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + KEY_HEIGHT / 2 - key.icon->height / 2, + key.icon); + } else { + // If shift is toggled use the shift key when available + strcpy(model->key_string, (model->shift && key.shift_key != 0) ? key.shift_key : key.key); + // Upper case if ctrl or alt was toggled true + if((model->ctrl && key.value == HID_KEYBOARD_L_CTRL) || + (model->alt && key.value == HID_KEYBOARD_L_ALT) || + (model->gui && key.value == HID_KEYBOARD_L_GUI)) { + usb_hid_keyboard_to_upper(model->key_string); + } + canvas_draw_str_aligned( + canvas, + MARGIN_LEFT + x * (KEY_WIDTH + KEY_PADDING) + keyWidth / 2 + 1, + MARGIN_TOP + y * (KEY_HEIGHT + KEY_PADDING) + KEY_HEIGHT / 2, + AlignCenter, + AlignCenter, + model->key_string); + } +} + +static void usb_hid_keyboard_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + UsbHidKeyboardModel* model = context; + + canvas_set_font(canvas, FontKeyboard); + // Start shifting the all keys up if on the next row (Scrolling) + uint8_t initY = model->y - 4 > 0 ? model->y - 4 : 0; + for(uint8_t y = initY; y < ROW_COUNT; y++) { + const UsbHidKeyboardKey* keyboardKeyRow = usb_hid_keyboard_keyset[y]; + uint8_t x = 0; + for(uint8_t i = 0; i < COLUMN_COUNT; i++) { + UsbHidKeyboardKey key = keyboardKeyRow[i]; + // Select when the button is hovered + // Select if the button is hovered within its width + // Select if back is clicked and its the backspace key + // Deselect when the button clicked or not hovered + bool keySelected = (x <= model->x && model->x < (x + key.width)) && y == model->y; + bool backSelected = model->back_pressed && key.value == HID_KEYBOARD_DELETE; + usb_hid_keyboard_draw_key( + canvas, + model, + x, + y - initY, + key, + (!model->ok_pressed && keySelected) || backSelected); + x += key.width; + } + } +} + +static uint8_t usb_hid_keyboard_get_selected_key(UsbHidKeyboardModel* model) { + UsbHidKeyboardKey key = usb_hid_keyboard_keyset[model->y][model->x]; + // Use upper case if shift is toggled + bool useUppercase = model->shift; + // Check if the key has an upper case version + bool hasUppercase = key.shift_key != 0; + if(useUppercase && hasUppercase) + return key.value; + else + return key.value; +} + +static void + usb_hid_keyboard_get_select_key(UsbHidKeyboardModel* model, UsbHidKeyboardPoint delta) { + // Keep going until a valid spot is found, this allows for nulls and zero width keys in the map + do { + if(((int8_t)model->y) + delta.y < 0) + model->y = ROW_COUNT - 1; + else + model->y = (model->y + delta.y) % ROW_COUNT; + } while(delta.y != 0 && usb_hid_keyboard_keyset[model->y][model->x].value == 0); + + do { + if(((int8_t)model->x) + delta.x < 0) + model->x = COLUMN_COUNT - 1; + else + model->x = (model->x + delta.x) % COLUMN_COUNT; + } while(delta.x != 0 && usb_hid_keyboard_keyset[model->y][model->x].width == + 0); // Skip zero width keys, pretend they are one key +} + +static void usb_hid_keyboard_process(UsbHidKeyboard* usb_hid_keyboard, InputEvent* event) { + with_view_model( + usb_hid_keyboard->view, + UsbHidKeyboardModel * model, + { + if(event->key == InputKeyOk) { + if(event->type == InputTypePress) { + model->ok_pressed = true; + } else if(event->type == InputTypeLong || event->type == InputTypeShort) { + model->last_key_code = usb_hid_keyboard_get_selected_key(model); + + // Toggle the modifier key when clicked, and click the key + if(model->last_key_code == HID_KEYBOARD_L_SHIFT) { + model->shift = !model->shift; + if(model->shift) + model->modifier_code |= KEY_MOD_LEFT_SHIFT; + else + model->modifier_code &= ~KEY_MOD_LEFT_SHIFT; + } else if(model->last_key_code == HID_KEYBOARD_L_ALT) { + model->alt = !model->alt; + if(model->alt) + model->modifier_code |= KEY_MOD_LEFT_ALT; + else + model->modifier_code &= ~KEY_MOD_LEFT_ALT; + } else if(model->last_key_code == HID_KEYBOARD_L_CTRL) { + model->ctrl = !model->ctrl; + if(model->ctrl) + model->modifier_code |= KEY_MOD_LEFT_CTRL; + else + model->modifier_code &= ~KEY_MOD_LEFT_CTRL; + } else if(model->last_key_code == HID_KEYBOARD_L_GUI) { + model->gui = !model->gui; + if(model->gui) + model->modifier_code |= KEY_MOD_LEFT_GUI; + else + model->modifier_code &= ~KEY_MOD_LEFT_GUI; + } + furi_hal_hid_kb_press(model->modifier_code | model->last_key_code); + } else if(event->type == InputTypeRelease) { + // Release happens after short and long presses + furi_hal_hid_kb_release(model->modifier_code | model->last_key_code); + model->ok_pressed = false; + } + } else if(event->key == InputKeyBack) { + // If back is pressed for a short time, backspace + if(event->type == InputTypePress) { + model->back_pressed = true; + } else if(event->type == InputTypeShort) { + furi_hal_hid_kb_press(HID_KEYBOARD_DELETE); + furi_hal_hid_kb_release(HID_KEYBOARD_DELETE); + } else if(event->type == InputTypeRelease) { + model->back_pressed = false; + } + } else if(event->type == InputTypePress || event->type == InputTypeRepeat) { + // Cycle the selected keys + if(event->key == InputKeyUp) { + usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = 0, .y = -1}); + } else if(event->key == InputKeyDown) { + usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = 0, .y = 1}); + } else if(event->key == InputKeyLeft) { + usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = -1, .y = 0}); + } else if(event->key == InputKeyRight) { + usb_hid_keyboard_get_select_key(model, (UsbHidKeyboardPoint){.x = 1, .y = 0}); + } + } + }, + true); +} + +static bool usb_hid_keyboard_input_callback(InputEvent* event, void* context) { + furi_assert(context); + UsbHidKeyboard* usb_hid_keyboard = context; + bool consumed = false; + + if(event->type == InputTypeLong && event->key == InputKeyBack) { + furi_hal_hid_kb_release_all(); + } else { + usb_hid_keyboard_process(usb_hid_keyboard, event); + consumed = true; + } + + return consumed; +} + +UsbHidKeyboard* usb_hid_keyboard_alloc() { + UsbHidKeyboard* usb_hid_keyboard = malloc(sizeof(UsbHidKeyboard)); + + usb_hid_keyboard->view = view_alloc(); + view_set_context(usb_hid_keyboard->view, usb_hid_keyboard); + view_allocate_model(usb_hid_keyboard->view, ViewModelTypeLocking, sizeof(UsbHidKeyboardModel)); + view_set_draw_callback(usb_hid_keyboard->view, usb_hid_keyboard_draw_callback); + view_set_input_callback(usb_hid_keyboard->view, usb_hid_keyboard_input_callback); + + with_view_model( + usb_hid_keyboard->view, UsbHidKeyboardModel * model, { model->connected = true; }, true); + + return usb_hid_keyboard; +} + +void usb_hid_keyboard_free(UsbHidKeyboard* usb_hid_keyboard) { + furi_assert(usb_hid_keyboard); + view_free(usb_hid_keyboard->view); + free(usb_hid_keyboard); +} + +View* usb_hid_keyboard_get_view(UsbHidKeyboard* usb_hid_keyboard) { + furi_assert(usb_hid_keyboard); + return usb_hid_keyboard->view; +} \ No newline at end of file diff --git a/applications/plugins/usbkeyboard/views/usb_hid_keyboard.h b/applications/plugins/usbkeyboard/views/usb_hid_keyboard.h new file mode 100644 index 000000000..4dee5fbee --- /dev/null +++ b/applications/plugins/usbkeyboard/views/usb_hid_keyboard.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +typedef struct UsbHidKeyboard UsbHidKeyboard; + +UsbHidKeyboard* usb_hid_keyboard_alloc(); + +void usb_hid_keyboard_free(UsbHidKeyboard* usb_hid_keyboard); + +View* usb_hid_keyboard_get_view(UsbHidKeyboard* usb_hid_keyboard); + +void usb_hid_keyboard_set_connected_status(UsbHidKeyboard* usb_hid_keyboard, bool connected); diff --git a/applications/plugins/usbkeyboard/views/usb_hid_media.c b/applications/plugins/usbkeyboard/views/usb_hid_media.c new file mode 100644 index 000000000..520d04717 --- /dev/null +++ b/applications/plugins/usbkeyboard/views/usb_hid_media.c @@ -0,0 +1,200 @@ +#include "usb_hid_media.h" +#include +#include +#include + +struct UsbHidMedia { + View* view; +}; + +typedef struct { + bool left_pressed; + bool up_pressed; + bool right_pressed; + bool down_pressed; + bool ok_pressed; + bool connected; +} UsbHidMediaModel; + +static void usb_hid_media_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_dot(canvas, x, y - 1); + } else if(dir == CanvasDirectionTopToBottom) { + canvas_draw_dot(canvas, x, y + 1); + } else if(dir == CanvasDirectionRightToLeft) { + canvas_draw_dot(canvas, x - 1, y); + } else if(dir == CanvasDirectionLeftToRight) { + canvas_draw_dot(canvas, x + 1, y); + } +} + +static void usb_hid_media_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + UsbHidMediaModel* model = context; + + canvas_set_font(canvas, FontPrimary); + elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Media"); + 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, 12, &I_Volup_8x6); + 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, 45, &I_Voldwn_6x6); + 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); + } + usb_hid_media_draw_arrow(canvas, 82, 31, CanvasDirectionRightToLeft); + usb_hid_media_draw_arrow(canvas, 86, 31, CanvasDirectionRightToLeft); + 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); + } + usb_hid_media_draw_arrow(canvas, 112, 31, CanvasDirectionLeftToRight); + usb_hid_media_draw_arrow(canvas, 116, 31, CanvasDirectionLeftToRight); + canvas_set_color(canvas, ColorBlack); + + // Ok + if(model->ok_pressed) { + canvas_draw_icon(canvas, 93, 25, &I_Pressed_Button_13x13); + canvas_set_color(canvas, ColorWhite); + } + usb_hid_media_draw_arrow(canvas, 96, 31, CanvasDirectionLeftToRight); + canvas_draw_line(canvas, 100, 29, 100, 33); + canvas_draw_line(canvas, 102, 29, 102, 33); + canvas_set_color(canvas, ColorBlack); + + // 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 usb_hid_media_process_press(UsbHidMedia* usb_hid_media, InputEvent* event) { + with_view_model( + usb_hid_media->view, + UsbHidMediaModel * model, + { + if(event->key == InputKeyUp) { + model->up_pressed = true; + furi_hal_hid_consumer_key_press(HID_CONSUMER_VOLUME_INCREMENT); + } else if(event->key == InputKeyDown) { + model->down_pressed = true; + furi_hal_hid_consumer_key_press(HID_CONSUMER_VOLUME_DECREMENT); + } else if(event->key == InputKeyLeft) { + model->left_pressed = true; + furi_hal_hid_consumer_key_press(HID_CONSUMER_SCAN_PREVIOUS_TRACK); + } else if(event->key == InputKeyRight) { + model->right_pressed = true; + furi_hal_hid_consumer_key_press(HID_CONSUMER_SCAN_NEXT_TRACK); + } else if(event->key == InputKeyOk) { + model->ok_pressed = true; + furi_hal_hid_consumer_key_press(HID_CONSUMER_PLAY_PAUSE); + } + }, + true); +} + +static void hid_media_process_release(UsbHidMedia* usb_hid_media, InputEvent* event) { + with_view_model( + usb_hid_media->view, + UsbHidMediaModel * model, + { + if(event->key == InputKeyUp) { + model->up_pressed = false; + furi_hal_hid_consumer_key_release(HID_CONSUMER_VOLUME_INCREMENT); + } else if(event->key == InputKeyDown) { + model->down_pressed = false; + furi_hal_hid_consumer_key_release(HID_CONSUMER_VOLUME_DECREMENT); + } else if(event->key == InputKeyLeft) { + model->left_pressed = false; + furi_hal_hid_consumer_key_release(HID_CONSUMER_SCAN_PREVIOUS_TRACK); + } else if(event->key == InputKeyRight) { + model->right_pressed = false; + furi_hal_hid_consumer_key_release(HID_CONSUMER_SCAN_NEXT_TRACK); + } else if(event->key == InputKeyOk) { + model->ok_pressed = false; + furi_hal_hid_consumer_key_release(HID_CONSUMER_PLAY_PAUSE); + } + }, + true); +} + +static bool usb_hid_media_input_callback(InputEvent* event, void* context) { + furi_assert(context); + UsbHidMedia* usb_hid_media = context; + bool consumed = false; + + if(event->type == InputTypePress) { + usb_hid_media_process_press(usb_hid_media, event); + consumed = true; + } else if(event->type == InputTypeRelease) { + hid_media_process_release(usb_hid_media, event); + consumed = true; + } else if(event->type == InputTypeShort) { + if(event->key == InputKeyBack) { + furi_hal_hid_kb_release_all(); + } + } + + return consumed; +} + +UsbHidMedia* usb_hid_media_alloc() { + UsbHidMedia* usb_hid_media = malloc(sizeof(UsbHidMedia)); + usb_hid_media->view = view_alloc(); + view_set_context(usb_hid_media->view, usb_hid_media); + view_allocate_model(usb_hid_media->view, ViewModelTypeLocking, sizeof(UsbHidMediaModel)); + view_set_draw_callback(usb_hid_media->view, usb_hid_media_draw_callback); + view_set_input_callback(usb_hid_media->view, usb_hid_media_input_callback); + + with_view_model( + usb_hid_media->view, UsbHidMediaModel * model, { model->connected = true; }, true); + + return usb_hid_media; +} + +void usb_hid_media_free(UsbHidMedia* usb_hid_media) { + furi_assert(usb_hid_media); + view_free(usb_hid_media->view); + free(usb_hid_media); +} + +View* usb_hid_media_get_view(UsbHidMedia* usb_hid_media) { + furi_assert(usb_hid_media); + return usb_hid_media->view; +} + +void usb_hid_media_set_connected_status(UsbHidMedia* usb_hid_media, bool connected) { + furi_assert(usb_hid_media); + with_view_model( + usb_hid_media->view, UsbHidMediaModel * model, { model->connected = connected; }, true); +} diff --git a/applications/plugins/usbkeyboard/views/usb_hid_media.h b/applications/plugins/usbkeyboard/views/usb_hid_media.h new file mode 100644 index 000000000..441e2bd6d --- /dev/null +++ b/applications/plugins/usbkeyboard/views/usb_hid_media.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +typedef struct UsbHidMedia UsbHidMedia; + +UsbHidMedia* usb_hid_media_alloc(); + +void usb_hid_media_free(UsbHidMedia* usb_hid_media); + +View* usb_hid_media_get_view(UsbHidMedia* usb_hid_media); + +void usb_hid_media_set_connected_status(UsbHidMedia* usb_hid_media, bool connected); diff --git a/applications/plugins/usbkeyboard/views/usb_hid_mouse.c b/applications/plugins/usbkeyboard/views/usb_hid_mouse.c new file mode 100644 index 000000000..77067ac04 --- /dev/null +++ b/applications/plugins/usbkeyboard/views/usb_hid_mouse.c @@ -0,0 +1,214 @@ +#include "usb_hid_mouse.h" +#include +#include +#include + +struct UsbHidMouse { + View* view; +}; +#define MOUSE_MOVE_SHORT 5 +#define MOUSE_MOVE_LONG 20 + +typedef struct { + bool left_pressed; + bool up_pressed; + bool right_pressed; + bool down_pressed; + bool left_mouse_pressed; + bool left_mouse_held; + bool right_mouse_pressed; + bool connected; +} UsbHidMouseModel; + +static void usb_hid_mouse_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + UsbHidMouseModel* 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, "Mouse"); + canvas_set_font(canvas, FontSecondary); + + if(model->left_mouse_held == true) { + elements_multiline_text_aligned(canvas, 0, 62, AlignLeft, AlignBottom, "Selecting..."); + } else { + 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"); + } + + // Keypad circles + canvas_draw_icon(canvas, 64, 8, &I_Circles_47x47); + + // Up + if(model->up_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 81, 9, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 84, 10, &I_Pin_arrow_up_7x9); + canvas_set_color(canvas, ColorBlack); + + // Down + if(model->down_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 81, 41, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 84, 43, &I_Pin_arrow_down_7x9); + canvas_set_color(canvas, ColorBlack); + + // Left + if(model->left_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 65, 25, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 67, 28, &I_Pin_arrow_left_9x7); + canvas_set_color(canvas, ColorBlack); + + // Right + if(model->right_pressed) { + canvas_set_bitmap_mode(canvas, 1); + canvas_draw_icon(canvas, 97, 25, &I_Pressed_Button_13x13); + canvas_set_bitmap_mode(canvas, 0); + canvas_set_color(canvas, ColorWhite); + } + canvas_draw_icon(canvas, 99, 28, &I_Pin_arrow_right_9x7); + canvas_set_color(canvas, ColorBlack); + + // Ok + if(model->left_mouse_pressed) { + canvas_draw_icon(canvas, 81, 25, &I_Ok_btn_pressed_13x13); + } else { + canvas_draw_icon(canvas, 83, 27, &I_Left_mouse_icon_9x9); + } + + // Back + if(model->right_mouse_pressed) { + canvas_draw_icon(canvas, 108, 48, &I_Ok_btn_pressed_13x13); + } else { + canvas_draw_icon(canvas, 110, 50, &I_Right_mouse_icon_9x9); + } +} + +static void usb_hid_mouse_process(UsbHidMouse* usb_hid_mouse, InputEvent* event) { + with_view_model( + usb_hid_mouse->view, + UsbHidMouseModel * model, + { + if(event->key == InputKeyBack) { + if(event->type == InputTypeShort) { + furi_hal_hid_mouse_press(HID_MOUSE_BTN_RIGHT); + furi_hal_hid_mouse_release(HID_MOUSE_BTN_RIGHT); + } else if(event->type == InputTypePress) { + model->right_mouse_pressed = true; + } else if(event->type == InputTypeRelease) { + model->right_mouse_pressed = false; + } + } else if(event->key == InputKeyOk) { + if(event->type == InputTypeShort) { + // Just release if it was being held before + if(!model->left_mouse_held) furi_hal_hid_mouse_press(HID_MOUSE_BTN_LEFT); + furi_hal_hid_mouse_release(HID_MOUSE_BTN_LEFT); + model->left_mouse_held = false; + } else if(event->type == InputTypeLong) { + furi_hal_hid_mouse_press(HID_MOUSE_BTN_LEFT); + model->left_mouse_held = true; + model->left_mouse_pressed = true; + } else if(event->type == InputTypePress) { + model->left_mouse_pressed = true; + } else if(event->type == InputTypeRelease) { + // Only release if it wasn't a long press + if(!model->left_mouse_held) model->left_mouse_pressed = false; + } + + } else if(event->key == InputKeyRight) { + if(event->type == InputTypePress) { + model->right_pressed = true; + furi_hal_hid_mouse_move(MOUSE_MOVE_SHORT, 0); + } else if(event->type == InputTypeRepeat) { + furi_hal_hid_mouse_move(MOUSE_MOVE_LONG, 0); + } else if(event->type == InputTypeRelease) { + model->right_pressed = false; + } + } else if(event->key == InputKeyLeft) { + if(event->type == InputTypePress) { + model->left_pressed = true; + furi_hal_hid_mouse_move(-MOUSE_MOVE_SHORT, 0); + } else if(event->type == InputTypeRepeat) { + furi_hal_hid_mouse_move(-MOUSE_MOVE_LONG, 0); + } else if(event->type == InputTypeRelease) { + model->left_pressed = false; + } + } else if(event->key == InputKeyDown) { + if(event->type == InputTypePress) { + model->down_pressed = true; + furi_hal_hid_mouse_move(0, MOUSE_MOVE_SHORT); + } else if(event->type == InputTypeRepeat) { + furi_hal_hid_mouse_move(0, MOUSE_MOVE_LONG); + } else if(event->type == InputTypeRelease) { + model->down_pressed = false; + } + } else if(event->key == InputKeyUp) { + if(event->type == InputTypePress) { + model->up_pressed = true; + furi_hal_hid_mouse_move(0, -MOUSE_MOVE_SHORT); + } else if(event->type == InputTypeRepeat) { + furi_hal_hid_mouse_move(0, -MOUSE_MOVE_LONG); + } else if(event->type == InputTypeRelease) { + model->up_pressed = false; + } + } + }, + true); +} + +static bool usb_hid_mouse_input_callback(InputEvent* event, void* context) { + furi_assert(context); + UsbHidMouse* usb_hid_mouse = context; + bool consumed = false; + + if(event->type == InputTypeLong && event->key == InputKeyBack) { + furi_hal_hid_mouse_release(HID_MOUSE_BTN_LEFT); + furi_hal_hid_mouse_release(HID_MOUSE_BTN_RIGHT); + } else { + usb_hid_mouse_process(usb_hid_mouse, event); + consumed = true; + } + + return consumed; +} + +UsbHidMouse* usb_hid_mouse_alloc() { + UsbHidMouse* usb_hid_mouse = malloc(sizeof(UsbHidMouse)); + usb_hid_mouse->view = view_alloc(); + view_set_context(usb_hid_mouse->view, usb_hid_mouse); + view_allocate_model(usb_hid_mouse->view, ViewModelTypeLocking, sizeof(UsbHidMouseModel)); + view_set_draw_callback(usb_hid_mouse->view, usb_hid_mouse_draw_callback); + view_set_input_callback(usb_hid_mouse->view, usb_hid_mouse_input_callback); + + with_view_model( + usb_hid_mouse->view, UsbHidMouseModel * model, { model->connected = true; }, true); + + return usb_hid_mouse; +} + +void usb_hid_mouse_free(UsbHidMouse* usb_hid_mouse) { + furi_assert(usb_hid_mouse); + view_free(usb_hid_mouse->view); + free(usb_hid_mouse); +} + +View* usb_hid_mouse_get_view(UsbHidMouse* usb_hid_mouse) { + furi_assert(usb_hid_mouse); + return usb_hid_mouse->view; +} diff --git a/applications/plugins/usbkeyboard/views/usb_hid_mouse.h b/applications/plugins/usbkeyboard/views/usb_hid_mouse.h new file mode 100644 index 000000000..e7eec9224 --- /dev/null +++ b/applications/plugins/usbkeyboard/views/usb_hid_mouse.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +typedef struct UsbHidMouse UsbHidMouse; + +UsbHidMouse* usb_hid_mouse_alloc(); + +void usb_hid_mouse_free(UsbHidMouse* usb_hid_mouse); + +View* usb_hid_mouse_get_view(UsbHidMouse* usb_hid_mouse); + +void usb_hid_mouse_set_connected_status(UsbHidMouse* usb_hid_mouse, bool connected); diff --git a/applications/plugins/wav_player/wav_player_view.c b/applications/plugins/wav_player/wav_player_view.c index 5308c0db7..fdf08cb21 100644 --- a/applications/plugins/wav_player/wav_player_view.c +++ b/applications/plugins/wav_player/wav_player_view.c @@ -146,52 +146,39 @@ View* wav_player_view_get_view(WavPlayerView* wav_view) { void wav_player_view_set_volume(WavPlayerView* wav_view, float volume) { furi_assert(wav_view); with_view_model( - wav_view->view, (WavPlayerViewModel * model) { - model->volume = volume; - return true; - }); + wav_view->view, WavPlayerViewModel * model, { model->volume = volume; }, true); } void wav_player_view_set_start(WavPlayerView* wav_view, size_t start) { furi_assert(wav_view); with_view_model( - wav_view->view, (WavPlayerViewModel * model) { - model->start = start; - return true; - }); + wav_view->view, WavPlayerViewModel * model, { model->start = start; }, true); } void wav_player_view_set_end(WavPlayerView* wav_view, size_t end) { furi_assert(wav_view); with_view_model( - wav_view->view, (WavPlayerViewModel * model) { - model->end = end; - return true; - }); + wav_view->view, WavPlayerViewModel * model, { model->end = end; }, true); } void wav_player_view_set_current(WavPlayerView* wav_view, size_t current) { furi_assert(wav_view); with_view_model( - wav_view->view, (WavPlayerViewModel * model) { - model->current = current; - return true; - }); + wav_view->view, WavPlayerViewModel * model, { model->current = current; }, true); } void wav_player_view_set_play(WavPlayerView* wav_view, bool play) { furi_assert(wav_view); with_view_model( - wav_view->view, (WavPlayerViewModel * model) { - model->play = play; - return true; - }); + wav_view->view, WavPlayerViewModel * model, { model->play = play; }, true); } void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count) { furi_assert(wav_view); with_view_model( - wav_view->view, (WavPlayerViewModel * model) { + wav_view->view, + WavPlayerViewModel * model, + { size_t inc = (data_count / DATA_COUNT) - 1; for(size_t i = 0; i < DATA_COUNT; i++) { @@ -199,8 +186,8 @@ void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t da if(model->data[i] > 42) model->data[i] = 42; data += inc; } - return true; - }); + }, + true); } void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCallback callback) { diff --git a/applications/services/desktop/desktop_settings.h b/applications/services/desktop/desktop_settings.h index c2d8dbd90..4ff55c6a9 100644 --- a/applications/services/desktop/desktop_settings.h +++ b/applications/services/desktop/desktop_settings.h @@ -8,7 +8,7 @@ #include #include -#define DESKTOP_SETTINGS_VER (5) +#define DESKTOP_SETTINGS_VER (6) #define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME) #define DESKTOP_SETTINGS_MAGIC (0x17) @@ -34,6 +34,9 @@ #define MAX_PIN_SIZE 10 #define MIN_PIN_SIZE 4 +#define MAX_APP_LENGTH 128 + +#define FAP_LOADER_APP_NAME "Applications" typedef struct { InputKey data[MAX_PIN_SIZE]; @@ -41,8 +44,13 @@ typedef struct { } PinCode; typedef struct { - uint16_t favorite_primary; - uint16_t favorite_secondary; + bool is_external; + char name_or_path[MAX_APP_LENGTH]; +} FavoriteApp; + +typedef struct { + FavoriteApp favorite_primary; + FavoriteApp favorite_secondary; PinCode pin_code; uint8_t is_locked; uint32_t auto_lock_delay_ms; diff --git a/applications/services/desktop/scenes/desktop_scene_main.c b/applications/services/desktop/scenes/desktop_scene_main.c index c66ada158..217725148 100644 --- a/applications/services/desktop/scenes/desktop_scene_main.c +++ b/applications/services/desktop/scenes/desktop_scene_main.c @@ -114,29 +114,39 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { case DesktopMainEventOpenFavoritePrimary: DESKTOP_SETTINGS_LOAD(&desktop->settings); - if(desktop->settings.favorite_primary < FLIPPER_APPS_COUNT) { + if(desktop->settings.favorite_primary.is_external) { LoaderStatus status = loader_start( - desktop->loader, FLIPPER_APPS[desktop->settings.favorite_primary].name, NULL); + desktop->loader, + FAP_LOADER_APP_NAME, + desktop->settings.favorite_primary.name_or_path); if(status != LoaderStatusOk) { FURI_LOG_E(TAG, "loader_start failed: %d", status); } } else { - FURI_LOG_E(TAG, "Can't find primary favorite application"); + LoaderStatus status = loader_start( + desktop->loader, desktop->settings.favorite_primary.name_or_path, NULL); + if(status != LoaderStatusOk) { + FURI_LOG_E(TAG, "loader_start failed: %d", status); + } } consumed = true; break; case DesktopMainEventOpenFavoriteSecondary: DESKTOP_SETTINGS_LOAD(&desktop->settings); - if(desktop->settings.favorite_secondary < FLIPPER_APPS_COUNT) { + if(desktop->settings.favorite_secondary.is_external) { LoaderStatus status = loader_start( desktop->loader, - FLIPPER_APPS[desktop->settings.favorite_secondary].name, - NULL); + FAP_LOADER_APP_NAME, + desktop->settings.favorite_secondary.name_or_path); if(status != LoaderStatusOk) { FURI_LOG_E(TAG, "loader_start failed: %d", status); } } else { - FURI_LOG_E(TAG, "Can't find secondary favorite application"); + LoaderStatus status = loader_start( + desktop->loader, desktop->settings.favorite_secondary.name_or_path, NULL); + if(status != LoaderStatusOk) { + FURI_LOG_E(TAG, "loader_start failed: %d", status); + } } consumed = true; break; @@ -165,8 +175,8 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { break; } case DesktopMainEventOpenGameMenu: { - LoaderStatus status = - loader_start(desktop->loader, "Applications", EXT_PATH("/apps/Games/Snake.fap")); + LoaderStatus status = loader_start( + desktop->loader, FAP_LOADER_APP_NAME, EXT_PATH("/apps/Games/Snake.fap")); if(status != LoaderStatusOk) { FURI_LOG_E(TAG, "loader_start failed: %d", status); } diff --git a/applications/services/desktop/views/desktop_view_debug.c b/applications/services/desktop/views/desktop_view_debug.c index c965432f1..f9c8aedc2 100644 --- a/applications/services/desktop/views/desktop_view_debug.c +++ b/applications/services/desktop/views/desktop_view_debug.c @@ -124,16 +124,17 @@ bool desktop_debug_input(InputEvent* event, void* context) { DesktopViewStatsScreens current = 0; with_view_model( - debug_view->view, (DesktopDebugViewModel * model) { - + debug_view->view, + DesktopDebugViewModel * model, + { #ifdef SRV_DOLPHIN_STATE_DEBUG if((event->key == InputKeyDown) || (event->key == InputKeyUp)) { model->screen = !model->screen; } #endif current = model->screen; - return true; - }); + }, + true); size_t count = (event->type == InputTypeRepeat) ? 10 : 1; if(current == DesktopViewStatsMeta) { @@ -181,20 +182,19 @@ void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view) { Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); DolphinStats stats = dolphin_stats(dolphin); with_view_model( - debug_view->view, (DesktopDebugViewModel * model) { + debug_view->view, + DesktopDebugViewModel * model, + { model->icounter = stats.icounter; model->butthurt = stats.butthurt; model->timestamp = stats.timestamp; - return true; - }); + }, + true); furi_record_close(RECORD_DOLPHIN); } void desktop_debug_reset_screen_idx(DesktopDebugView* debug_view) { with_view_model( - debug_view->view, (DesktopDebugViewModel * model) { - model->screen = 0; - return true; - }); + debug_view->view, DesktopDebugViewModel * model, { model->screen = 0; }, true); } diff --git a/applications/services/desktop/views/desktop_view_lock_menu.c b/applications/services/desktop/views/desktop_view_lock_menu.c index 294191bf2..8cb8a7a12 100644 --- a/applications/services/desktop/views/desktop_view_lock_menu.c +++ b/applications/services/desktop/views/desktop_view_lock_menu.c @@ -24,27 +24,24 @@ void desktop_lock_menu_set_callback( void desktop_lock_menu_set_pin_state(DesktopLockMenuView* lock_menu, bool pin_is_set) { with_view_model( - lock_menu->view, (DesktopLockMenuViewModel * model) { - model->pin_is_set = pin_is_set; - return true; - }); + lock_menu->view, + DesktopLockMenuViewModel * model, + { model->pin_is_set = pin_is_set; }, + true); } void desktop_lock_menu_set_dummy_mode_state(DesktopLockMenuView* lock_menu, bool dummy_mode) { with_view_model( - lock_menu->view, (DesktopLockMenuViewModel * model) { - model->dummy_mode = dummy_mode; - return true; - }); + lock_menu->view, + DesktopLockMenuViewModel * model, + { model->dummy_mode = dummy_mode; }, + true); } void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) { furi_assert(idx < DesktopLockMenuIndexTotalCount); with_view_model( - lock_menu->view, (DesktopLockMenuViewModel * model) { - model->idx = idx; - return true; - }); + lock_menu->view, DesktopLockMenuViewModel * model, { model->idx = idx; }, true); } void desktop_lock_menu_draw_callback(Canvas* canvas, void* model) { @@ -95,10 +92,12 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { uint8_t idx = 0; bool consumed = false; bool dummy_mode = false; + bool update = false; with_view_model( - lock_menu->view, (DesktopLockMenuViewModel * model) { - bool ret = false; + lock_menu->view, + DesktopLockMenuViewModel * model, + { if((event->type == InputTypeShort) || (event->type == InputTypeRepeat)) { if(event->key == InputKeyUp) { if(model->idx == 0) { @@ -106,7 +105,7 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { } else { model->idx = CLAMP(model->idx - 1, DesktopLockMenuIndexTotalCount - 1, 0); } - ret = true; + update = true; consumed = true; } else if(event->key == InputKeyDown) { if(model->idx == DesktopLockMenuIndexTotalCount - 1) { @@ -114,14 +113,14 @@ bool desktop_lock_menu_input_callback(InputEvent* event, void* context) { } else { model->idx = CLAMP(model->idx + 1, DesktopLockMenuIndexTotalCount - 1, 0); } - ret = true; + update = true; consumed = true; } } idx = model->idx; dummy_mode = model->dummy_mode; - return ret; - }); + }, + update); if(event->key == InputKeyOk) { if((idx == DesktopLockMenuIndexLock) && (event->type == InputTypeShort)) { diff --git a/applications/services/gui/modules/button_menu.c b/applications/services/gui/modules/button_menu.c index 1dce014d8..37a04326a 100644 --- a/applications/services/gui/modules/button_menu.c +++ b/applications/services/gui/modules/button_menu.c @@ -148,28 +148,32 @@ static void button_menu_process_up(ButtonMenu* button_menu) { furi_assert(button_menu); with_view_model( - button_menu->view, (ButtonMenuModel * model) { + button_menu->view, + ButtonMenuModel * model, + { if(model->position > 0) { model->position--; } else { model->position = ButtonMenuItemArray_size(model->items) - 1; } - return true; - }); + }, + true); } static void button_menu_process_down(ButtonMenu* button_menu) { furi_assert(button_menu); with_view_model( - button_menu->view, (ButtonMenuModel * model) { + button_menu->view, + ButtonMenuModel * model, + { if(model->position < (ButtonMenuItemArray_size(model->items) - 1)) { model->position++; } else { model->position = 0; } - return true; - }); + }, + true); } static void button_menu_process_ok(ButtonMenu* button_menu, InputType type) { @@ -178,12 +182,14 @@ static void button_menu_process_ok(ButtonMenu* button_menu, InputType type) { ButtonMenuItem* item = NULL; with_view_model( - button_menu->view, (ButtonMenuModel * model) { + button_menu->view, + ButtonMenuModel * model, + { if(model->position < (ButtonMenuItemArray_size(model->items))) { item = ButtonMenuItemArray_get(model->items, model->position); } - return false; - }); + }, + false); if(item) { if(item->type == ButtonMenuItemTypeControl) { @@ -248,22 +254,21 @@ void button_menu_reset(ButtonMenu* button_menu) { furi_assert(button_menu); with_view_model( - button_menu->view, (ButtonMenuModel * model) { + button_menu->view, + ButtonMenuModel * model, + { ButtonMenuItemArray_reset(model->items); model->position = 0; model->header = NULL; - return true; - }); + }, + true); } void button_menu_set_header(ButtonMenu* button_menu, const char* header) { furi_assert(button_menu); with_view_model( - button_menu->view, (ButtonMenuModel * model) { - model->header = header; - return true; - }); + button_menu->view, ButtonMenuModel * model, { model->header = header; }, true); } ButtonMenuItem* button_menu_add_item( @@ -278,15 +283,17 @@ ButtonMenuItem* button_menu_add_item( furi_assert(button_menu); with_view_model( - button_menu->view, (ButtonMenuModel * model) { + button_menu->view, + ButtonMenuModel * model, + { item = ButtonMenuItemArray_push_new(model->items); item->label = label; item->index = index; item->type = type; item->callback = callback; item->callback_context = callback_context; - return true; - }); + }, + true); return item; } @@ -301,12 +308,14 @@ ButtonMenu* button_menu_alloc(void) { view_set_input_callback(button_menu->view, button_menu_view_input_callback); with_view_model( - button_menu->view, (ButtonMenuModel * model) { + button_menu->view, + ButtonMenuModel * model, + { ButtonMenuItemArray_init(model->items); model->position = 0; model->header = NULL; - return true; - }); + }, + true); button_menu->freeze_input = false; return button_menu; @@ -316,10 +325,10 @@ void button_menu_free(ButtonMenu* button_menu) { furi_assert(button_menu); with_view_model( - button_menu->view, (ButtonMenuModel * model) { - ButtonMenuItemArray_clear(model->items); - return true; - }); + button_menu->view, + ButtonMenuModel * model, + { ButtonMenuItemArray_clear(model->items); }, + true); view_free(button_menu->view); free(button_menu); } @@ -328,7 +337,9 @@ void button_menu_set_selected_item(ButtonMenu* button_menu, uint32_t index) { furi_assert(button_menu); with_view_model( - button_menu->view, (ButtonMenuModel * model) { + button_menu->view, + ButtonMenuModel * model, + { uint8_t item_position = 0; ButtonMenuItemArray_it_t it; for(ButtonMenuItemArray_it(it, model->items); !ButtonMenuItemArray_end_p(it); @@ -338,6 +349,6 @@ void button_menu_set_selected_item(ButtonMenu* button_menu, uint32_t index) { break; } } - return true; - }); + }, + true); } diff --git a/applications/services/gui/modules/button_panel.c b/applications/services/gui/modules/button_panel.c index 66e8f36a3..32e303f9b 100644 --- a/applications/services/gui/modules/button_panel.c +++ b/applications/services/gui/modules/button_panel.c @@ -70,26 +70,30 @@ ButtonPanel* button_panel_alloc() { view_set_input_callback(button_panel->view, button_panel_view_input_callback); with_view_model( - button_panel->view, (ButtonPanelModel * model) { + button_panel->view, + ButtonPanelModel * model, + { model->reserve_x = 0; model->reserve_y = 0; model->selected_item_x = 0; model->selected_item_y = 0; ButtonMatrix_init(model->button_matrix); LabelList_init(model->labels); - return true; - }); + }, + true); return button_panel; } void button_panel_reset_selection(ButtonPanel* button_panel) { with_view_model( - button_panel->view, (ButtonPanelModel * model) { + button_panel->view, + ButtonPanelModel * model, + { model->selected_item_x = 0; model->selected_item_y = 0; - return true; - }); + }, + true); } void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t reserve_y) { @@ -97,7 +101,9 @@ void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t re furi_check(reserve_y > 0); with_view_model( - button_panel->view, (ButtonPanelModel * model) { + button_panel->view, + ButtonPanelModel * model, + { model->reserve_x = reserve_x; model->reserve_y = reserve_y; ButtonMatrix_reserve(model->button_matrix, model->reserve_y); @@ -108,8 +114,8 @@ void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t re // TODO: do we need to clear allocated memory of ptr-s to ButtonItem ?? } LabelList_init(model->labels); - return true; - }); + }, + true); } void button_panel_free(ButtonPanel* button_panel) { @@ -118,11 +124,13 @@ void button_panel_free(ButtonPanel* button_panel) { button_panel_reset(button_panel); with_view_model( - button_panel->view, (ButtonPanelModel * model) { + button_panel->view, + ButtonPanelModel * model, + { LabelList_clear(model->labels); ButtonMatrix_clear(model->button_matrix); - return true; - }); + }, + true); view_free(button_panel->view); free(button_panel); @@ -132,7 +140,9 @@ void button_panel_reset(ButtonPanel* button_panel) { furi_assert(button_panel); with_view_model( - button_panel->view, (ButtonPanelModel * model) { + button_panel->view, + ButtonPanelModel * model, + { for(size_t x = 0; x < model->reserve_x; ++x) { for(size_t y = 0; y < model->reserve_y; ++y) { ButtonItem** button_item = button_panel_get_item(model, x, y); @@ -146,8 +156,8 @@ void button_panel_reset(ButtonPanel* button_panel) { model->selected_item_y = 0; LabelList_reset(model->labels); ButtonMatrix_reset(model->button_matrix); - return true; - }); + }, + true); } static ButtonItem** button_panel_get_item(ButtonPanelModel* model, size_t x, size_t y) { @@ -174,7 +184,9 @@ void button_panel_add_item( furi_assert(button_panel); with_view_model( - button_panel->view, (ButtonPanelModel * model) { + button_panel->view, + ButtonPanelModel * model, + { ButtonItem** button_item_ptr = button_panel_get_item(model, matrix_place_x, matrix_place_y); furi_check(*button_item_ptr == NULL); @@ -187,8 +199,8 @@ void button_panel_add_item( button_item->icon.name = icon_name; button_item->icon.name_selected = icon_name_selected; button_item->index = index; - return true; - }); + }, + true); } View* button_panel_get_view(ButtonPanel* button_panel) { @@ -225,114 +237,123 @@ static void button_panel_view_draw_callback(Canvas* canvas, void* _model) { static void button_panel_process_down(ButtonPanel* button_panel) { with_view_model( - button_panel->view, (ButtonPanelModel * model) { + button_panel->view, + ButtonPanelModel * model, + { uint16_t new_selected_item_x = model->selected_item_x; uint16_t new_selected_item_y = model->selected_item_y; size_t i; - if(new_selected_item_y >= (model->reserve_y - 1)) return false; + if(new_selected_item_y < (model->reserve_y - 1)) { + ++new_selected_item_y; - ++new_selected_item_y; - - for(i = 0; i < model->reserve_x; ++i) { - new_selected_item_x = (model->selected_item_x + i) % model->reserve_x; - if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) { - break; + for(i = 0; i < model->reserve_x; ++i) { + new_selected_item_x = (model->selected_item_x + i) % model->reserve_x; + if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) { + break; + } + } + if(i != model->reserve_x) { + model->selected_item_x = new_selected_item_x; + model->selected_item_y = new_selected_item_y; } } - if(i == model->reserve_x) return false; - - model->selected_item_x = new_selected_item_x; - model->selected_item_y = new_selected_item_y; - - return true; - }); + }, + true); } static void button_panel_process_up(ButtonPanel* button_panel) { with_view_model( - button_panel->view, (ButtonPanelModel * model) { + button_panel->view, + ButtonPanelModel * model, + { size_t new_selected_item_x = model->selected_item_x; size_t new_selected_item_y = model->selected_item_y; size_t i; - if(new_selected_item_y <= 0) return false; + if(new_selected_item_y > 0) { + --new_selected_item_y; - --new_selected_item_y; - - for(i = 0; i < model->reserve_x; ++i) { - new_selected_item_x = (model->selected_item_x + i) % model->reserve_x; - if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) { - break; + for(i = 0; i < model->reserve_x; ++i) { + new_selected_item_x = (model->selected_item_x + i) % model->reserve_x; + if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) { + break; + } + } + if(i != model->reserve_x) { + model->selected_item_x = new_selected_item_x; + model->selected_item_y = new_selected_item_y; } } - if(i == model->reserve_x) return false; - - model->selected_item_x = new_selected_item_x; - model->selected_item_y = new_selected_item_y; - return true; - }); + }, + true); } static void button_panel_process_left(ButtonPanel* button_panel) { with_view_model( - button_panel->view, (ButtonPanelModel * model) { + button_panel->view, + ButtonPanelModel * model, + { size_t new_selected_item_x = model->selected_item_x; size_t new_selected_item_y = model->selected_item_y; size_t i; - if(new_selected_item_x <= 0) return false; + if(new_selected_item_x > 0) { + --new_selected_item_x; - --new_selected_item_x; - - for(i = 0; i < model->reserve_y; ++i) { - new_selected_item_y = (model->selected_item_y + i) % model->reserve_y; - if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) { - break; + for(i = 0; i < model->reserve_y; ++i) { + new_selected_item_y = (model->selected_item_y + i) % model->reserve_y; + if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) { + break; + } + } + if(i != model->reserve_y) { + model->selected_item_x = new_selected_item_x; + model->selected_item_y = new_selected_item_y; } } - if(i == model->reserve_y) return false; - - model->selected_item_x = new_selected_item_x; - model->selected_item_y = new_selected_item_y; - return true; - }); + }, + true); } static void button_panel_process_right(ButtonPanel* button_panel) { with_view_model( - button_panel->view, (ButtonPanelModel * model) { + button_panel->view, + ButtonPanelModel * model, + { uint16_t new_selected_item_x = model->selected_item_x; uint16_t new_selected_item_y = model->selected_item_y; size_t i; - if(new_selected_item_x >= (model->reserve_x - 1)) return false; + if(new_selected_item_x < (model->reserve_x - 1)) { + ++new_selected_item_x; - ++new_selected_item_x; - - for(i = 0; i < model->reserve_y; ++i) { - new_selected_item_y = (model->selected_item_y + i) % model->reserve_y; - if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) { - break; + for(i = 0; i < model->reserve_y; ++i) { + new_selected_item_y = (model->selected_item_y + i) % model->reserve_y; + if(*button_panel_get_item(model, new_selected_item_x, new_selected_item_y)) { + break; + } + } + if(i != model->reserve_y) { + model->selected_item_x = new_selected_item_x; + model->selected_item_y = new_selected_item_y; } } - if(i == model->reserve_y) return false; - - model->selected_item_x = new_selected_item_x; - model->selected_item_y = new_selected_item_y; - return true; - }); + }, + true); } void button_panel_process_ok(ButtonPanel* button_panel) { ButtonItem* button_item = NULL; with_view_model( - button_panel->view, (ButtonPanelModel * model) { + button_panel->view, + ButtonPanelModel * model, + { button_item = *button_panel_get_item(model, model->selected_item_x, model->selected_item_y); - return true; - }); + }, + true); if(button_item && button_item->callback) { button_item->callback(button_item->callback_context, button_item->index); @@ -383,12 +404,14 @@ void button_panel_add_label( furi_assert(button_panel); with_view_model( - button_panel->view, (ButtonPanelModel * model) { + button_panel->view, + ButtonPanelModel * model, + { LabelElement* label = LabelList_push_raw(model->labels); label->x = x; label->y = y; label->font = font; label->str = label_str; - return true; - }); + }, + true); } diff --git a/applications/services/gui/modules/byte_input.c b/applications/services/gui/modules/byte_input.c index bb18a107a..8d7e7fd4f 100644 --- a/applications/services/gui/modules/byte_input.c +++ b/applications/services/gui/modules/byte_input.c @@ -618,42 +618,30 @@ static bool byte_input_view_input_callback(InputEvent* event, void* context) { switch(event->key) { case InputKeyLeft: with_view_model( - byte_input->view, (ByteInputModel * model) { - byte_input_handle_left(model); - return true; - }); + byte_input->view, ByteInputModel * model, { byte_input_handle_left(model); }, true); consumed = true; break; case InputKeyRight: with_view_model( - byte_input->view, (ByteInputModel * model) { - byte_input_handle_right(model); - return true; - }); + byte_input->view, + ByteInputModel * model, + { byte_input_handle_right(model); }, + true); consumed = true; break; case InputKeyUp: with_view_model( - byte_input->view, (ByteInputModel * model) { - byte_input_handle_up(model); - return true; - }); + byte_input->view, ByteInputModel * model, { byte_input_handle_up(model); }, true); consumed = true; break; case InputKeyDown: with_view_model( - byte_input->view, (ByteInputModel * model) { - byte_input_handle_down(model); - return true; - }); + byte_input->view, ByteInputModel * model, { byte_input_handle_down(model); }, true); consumed = true; break; case InputKeyOk: with_view_model( - byte_input->view, (ByteInputModel * model) { - byte_input_handle_ok(model); - return true; - }); + byte_input->view, ByteInputModel * model, { byte_input_handle_ok(model); }, true); consumed = true; break; default: @@ -664,10 +652,10 @@ static bool byte_input_view_input_callback(InputEvent* event, void* context) { if((event->type == InputTypeLong || event->type == InputTypeRepeat) && event->key == InputKeyBack) { with_view_model( - byte_input->view, (ByteInputModel * model) { - byte_input_clear_selected_byte(model); - return true; - }); + byte_input->view, + ByteInputModel * model, + { byte_input_clear_selected_byte(model); }, + true); consumed = true; } @@ -703,14 +691,16 @@ ByteInput* byte_input_alloc() { view_set_input_callback(byte_input->view, byte_input_view_input_callback); with_view_model( - byte_input->view, (ByteInputModel * model) { + byte_input->view, + ByteInputModel * model, + { model->header = ""; model->input_callback = NULL; model->changed_callback = NULL; model->callback_context = NULL; byte_input_reset_model_input_data(model); - return true; - }); + }, + true); return byte_input; } @@ -755,15 +745,17 @@ void byte_input_set_result_callback( uint8_t* bytes, uint8_t bytes_count) { with_view_model( - byte_input->view, (ByteInputModel * model) { + byte_input->view, + ByteInputModel * model, + { byte_input_reset_model_input_data(model); model->input_callback = input_callback; model->changed_callback = changed_callback; model->callback_context = callback_context; model->bytes = bytes; model->bytes_count = bytes_count; - return true; - }); + }, + true); } /** @@ -774,8 +766,5 @@ void byte_input_set_result_callback( */ void byte_input_set_header_text(ByteInput* byte_input, const char* text) { with_view_model( - byte_input->view, (ByteInputModel * model) { - model->header = text; - return true; - }); + byte_input->view, ByteInputModel * model, { model->header = text; }, true); } diff --git a/applications/services/gui/modules/dialog_ex.c b/applications/services/gui/modules/dialog_ex.c index dee2a0971..1cb467232 100644 --- a/applications/services/gui/modules/dialog_ex.c +++ b/applications/services/gui/modules/dialog_ex.c @@ -90,12 +90,14 @@ static bool dialog_ex_view_input_callback(InputEvent* event, void* context) { const char* right_text = NULL; with_view_model( - dialog_ex->view, (DialogExModel * model) { + dialog_ex->view, + DialogExModel * model, + { left_text = model->left_text; center_text = model->center_text; right_text = model->right_text; - return true; - }); + }, + true); if(dialog_ex->callback) { if(event->type == InputTypeShort) { @@ -149,7 +151,9 @@ DialogEx* dialog_ex_alloc() { view_set_draw_callback(dialog_ex->view, dialog_ex_view_draw_callback); view_set_input_callback(dialog_ex->view, dialog_ex_view_input_callback); with_view_model( - dialog_ex->view, (DialogExModel * model) { + dialog_ex->view, + DialogExModel * model, + { model->header.text = NULL; model->header.x = 0; model->header.y = 0; @@ -169,9 +173,8 @@ DialogEx* dialog_ex_alloc() { model->left_text = NULL; model->center_text = NULL; model->right_text = NULL; - - return true; - }); + }, + true); dialog_ex->enable_extended_events = false; return dialog_ex; } @@ -206,14 +209,16 @@ void dialog_ex_set_header( Align vertical) { furi_assert(dialog_ex); with_view_model( - dialog_ex->view, (DialogExModel * model) { + dialog_ex->view, + DialogExModel * model, + { model->header.text = text; model->header.x = x; model->header.y = y; model->header.horizontal = horizontal; model->header.vertical = vertical; - return true; - }); + }, + true); } void dialog_ex_set_text( @@ -225,52 +230,47 @@ void dialog_ex_set_text( Align vertical) { furi_assert(dialog_ex); with_view_model( - dialog_ex->view, (DialogExModel * model) { + dialog_ex->view, + DialogExModel * model, + { model->text.text = text; model->text.x = x; model->text.y = y; model->text.horizontal = horizontal; model->text.vertical = vertical; - return true; - }); + }, + true); } void dialog_ex_set_icon(DialogEx* dialog_ex, uint8_t x, uint8_t y, const Icon* icon) { furi_assert(dialog_ex); with_view_model( - dialog_ex->view, (DialogExModel * model) { + dialog_ex->view, + DialogExModel * model, + { model->icon.x = x; model->icon.y = y; model->icon.icon = icon; - return true; - }); + }, + true); } void dialog_ex_set_left_button_text(DialogEx* dialog_ex, const char* text) { furi_assert(dialog_ex); with_view_model( - dialog_ex->view, (DialogExModel * model) { - model->left_text = text; - return true; - }); + dialog_ex->view, DialogExModel * model, { model->left_text = text; }, true); } void dialog_ex_set_center_button_text(DialogEx* dialog_ex, const char* text) { furi_assert(dialog_ex); with_view_model( - dialog_ex->view, (DialogExModel * model) { - model->center_text = text; - return true; - }); + dialog_ex->view, DialogExModel * model, { model->center_text = text; }, true); } void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text) { furi_assert(dialog_ex); with_view_model( - dialog_ex->view, (DialogExModel * model) { - model->right_text = text; - return true; - }); + dialog_ex->view, DialogExModel * model, { model->right_text = text; }, true); } void dialog_ex_reset(DialogEx* dialog_ex) { @@ -279,15 +279,17 @@ void dialog_ex_reset(DialogEx* dialog_ex) { .text = NULL, .x = 0, .y = 0, .horizontal = AlignLeft, .vertical = AlignLeft}; IconElement clean_icon_el = {.icon = NULL, .x = 0, .y = 0}; with_view_model( - dialog_ex->view, (DialogExModel * model) { + dialog_ex->view, + DialogExModel * model, + { model->header = clean_text_el; model->text = clean_text_el; model->icon = clean_icon_el; model->left_text = NULL; model->center_text = NULL; model->right_text = NULL; - return true; - }); + }, + true); dialog_ex->context = NULL; dialog_ex->callback = NULL; } diff --git a/applications/services/gui/modules/file_browser.c b/applications/services/gui/modules/file_browser.c index 762fe87d5..60e78b01c 100644 --- a/applications/services/gui/modules/file_browser.c +++ b/applications/services/gui/modules/file_browser.c @@ -139,10 +139,7 @@ FileBrowser* file_browser_alloc(FuriString* result_path) { browser->result_path = result_path; with_view_model( - browser->view, (FileBrowserModel * model) { - items_array_init(model->items); - return false; - }); + browser->view, FileBrowserModel * model, { items_array_init(model->items); }, false); return browser; } @@ -151,10 +148,7 @@ void file_browser_free(FileBrowser* browser) { furi_assert(browser); with_view_model( - browser->view, (FileBrowserModel * model) { - items_array_clear(model->items); - return false; - }); + browser->view, FileBrowserModel * model, { items_array_clear(model->items); }, false); view_free(browser->view); free(browser); @@ -178,11 +172,13 @@ void file_browser_configure( browser->hide_ext = hide_ext; with_view_model( - browser->view, (FileBrowserModel * model) { + browser->view, + FileBrowserModel * model, + { model->file_icon = file_icon; model->hide_ext = hide_ext; - return false; - }); + }, + false); } void file_browser_start(FileBrowser* browser, FuriString* path) { @@ -199,14 +195,16 @@ void file_browser_stop(FileBrowser* browser) { furi_assert(browser); file_browser_worker_free(browser->worker); with_view_model( - browser->view, (FileBrowserModel * model) { + browser->view, + FileBrowserModel * model, + { items_array_reset(model->items); model->item_cnt = 0; model->item_idx = 0; model->array_offset = 0; model->list_offset = 0; - return false; - }); + }, + false); } void file_browser_set_callback(FileBrowser* browser, FileBrowserCallback callback, void* context) { @@ -257,7 +255,9 @@ static void browser_update_offset(FileBrowser* browser) { furi_assert(browser); with_view_model( - browser->view, (FileBrowserModel * model) { + browser->view, + FileBrowserModel * model, + { uint16_t bounds = model->item_cnt > (LIST_ITEMS - 1) ? 2 : model->item_cnt; if((model->item_cnt > (LIST_ITEMS - 1)) && @@ -272,9 +272,8 @@ static void browser_update_offset(FileBrowser* browser) { model->list_offset = CLAMP(model->item_idx - 1, (int32_t)model->item_cnt - bounds, 0); } - - return false; - }); + }, + false); } static void @@ -285,7 +284,9 @@ static void int32_t load_offset = 0; with_view_model( - browser->view, (FileBrowserModel * model) { + browser->view, + FileBrowserModel * model, + { items_array_reset(model->items); if(is_root) { model->item_cnt = item_cnt; @@ -303,8 +304,8 @@ static void model->is_root = is_root; model->list_loading = true; model->folder_loading = false; - return true; - }); + }, + true); browser_update_offset(browser); file_browser_worker_load(browser->worker, load_offset, ITEM_LIST_LEN_MAX); @@ -319,7 +320,9 @@ static void browser_list_load_cb(void* context, uint32_t list_load_offset) { back_item.type = BrowserItemTypeBack; with_view_model( - browser->view, (FileBrowserModel * model) { + browser->view, + FileBrowserModel * model, + { items_array_reset(model->items); model->array_offset = list_load_offset; if(!model->is_root) { @@ -329,8 +332,8 @@ static void browser_list_load_cb(void* context, uint32_t list_load_offset) { model->array_offset += 1; } } - return false; - }); + }, + true); BrowserItem_t_clear(&back_item); } @@ -371,11 +374,13 @@ static void } with_view_model( - browser->view, (FileBrowserModel * model) { + browser->view, + FileBrowserModel * model, + { items_array_push_back(model->items, item); // TODO: calculate if element is visible - return true; - }); + }, + true); furi_string_free(item.display_name); furi_string_free(item.path); if(item.custom_icon_data) { @@ -383,10 +388,7 @@ static void } } else { with_view_model( - browser->view, (FileBrowserModel * model) { - model->list_loading = false; - return true; - }); + browser->view, FileBrowserModel * model, { model->list_loading = false; }, true); } } @@ -395,10 +397,7 @@ static void browser_long_load_cb(void* context) { FileBrowser* browser = (FileBrowser*)context; with_view_model( - browser->view, (FileBrowserModel * model) { - model->folder_loading = true; - return true; - }); + browser->view, FileBrowserModel * model, { model->folder_loading = true; }, true); } static void browser_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) { @@ -508,17 +507,16 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { bool is_loading = false; with_view_model( - browser->view, (FileBrowserModel * model) { - is_loading = model->folder_loading; - return false; - }); + browser->view, FileBrowserModel * model, { is_loading = model->folder_loading; }, false); if(is_loading) { return false; } else if(event->key == InputKeyUp || event->key == InputKeyDown) { if(event->type == InputTypeShort || event->type == InputTypeRepeat) { with_view_model( - browser->view, (FileBrowserModel * model) { + browser->view, + FileBrowserModel * model, + { if(event->key == InputKeyUp) { model->item_idx = ((model->item_idx - 1) + model->item_cnt) % model->item_cnt; @@ -543,8 +541,8 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { browser->worker, load_offset, ITEM_LIST_LEN_MAX); } } - return true; - }); + }, + true); browser_update_offset(browser); consumed = true; } @@ -553,7 +551,9 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { BrowserItem_t* selected_item = NULL; int32_t select_index = 0; with_view_model( - browser->view, (FileBrowserModel * model) { + browser->view, + FileBrowserModel * model, + { if(browser_is_item_in_array(model, model->item_idx)) { selected_item = items_array_get(model->items, model->item_idx - model->array_offset); @@ -562,8 +562,8 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { select_index -= 1; } } - return false; - }); + }, + false); if(selected_item) { if(selected_item->type == BrowserItemTypeBack) { @@ -584,10 +584,7 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) { if(event->type == InputTypeShort) { bool is_root = false; with_view_model( - browser->view, (FileBrowserModel * model) { - is_root = model->is_root; - return false; - }); + browser->view, FileBrowserModel * model, { is_root = model->is_root; }, false); if(!is_root) { file_browser_worker_folder_exit(browser->worker); } diff --git a/applications/services/gui/modules/menu.c b/applications/services/gui/modules/menu.c index 67d46d5f3..db0717f77 100644 --- a/applications/services/gui/modules/menu.c +++ b/applications/services/gui/modules/menu.c @@ -103,25 +103,29 @@ static bool menu_input_callback(InputEvent* event, void* context) { static void menu_enter(void* context) { Menu* menu = context; with_view_model( - menu->view, (MenuModel * model) { + menu->view, + MenuModel * model, + { MenuItem* item = MenuItemArray_get(model->items, model->position); if(item && item->icon) { icon_animation_start(item->icon); } - return false; - }); + }, + false); } static void menu_exit(void* context) { Menu* menu = context; with_view_model( - menu->view, (MenuModel * model) { + menu->view, + MenuModel * model, + { MenuItem* item = MenuItemArray_get(model->items, model->position); if(item && item->icon) { icon_animation_stop(item->icon); } - return false; - }); + }, + false); } Menu* menu_alloc() { @@ -135,11 +139,13 @@ Menu* menu_alloc() { view_set_exit_callback(menu->view, menu_exit); with_view_model( - menu->view, (MenuModel * model) { + menu->view, + MenuModel * model, + { MenuItemArray_init(model->items); model->position = 0; - return true; - }); + }, + true); return menu; } @@ -168,7 +174,9 @@ void menu_add_item( MenuItem* item = NULL; with_view_model( - menu->view, (MenuModel * model) { + menu->view, + MenuModel * model, + { item = MenuItemArray_push_new(model->items); item->label = label; item->icon = icon ? icon_animation_alloc(icon) : icon_animation_alloc(&A_Plugins_14); @@ -176,14 +184,16 @@ void menu_add_item( item->index = index; item->callback = callback; item->callback_context = context; - return true; - }); + }, + true); } void menu_reset(Menu* menu) { furi_assert(menu); with_view_model( - menu->view, (MenuModel * model) { + menu->view, + MenuModel * model, + { for M_EACH(item, model->items, MenuItemArray_t) { icon_animation_stop(item->icon); @@ -192,25 +202,27 @@ void menu_reset(Menu* menu) { MenuItemArray_reset(model->items); model->position = 0; - return true; - }); + }, + true); } void menu_set_selected_item(Menu* menu, uint32_t index) { with_view_model( - menu->view, (MenuModel * model) { - if(index >= MenuItemArray_size(model->items)) { - return false; + menu->view, + MenuModel * model, + { + if(index < MenuItemArray_size(model->items)) { + model->position = index; } - - model->position = index; - return true; - }); + }, + true); } static void menu_process_up(Menu* menu) { with_view_model( - menu->view, (MenuModel * model) { + menu->view, + MenuModel * model, + { MenuItem* item = MenuItemArray_get(model->items, model->position); if(item && item->icon) { icon_animation_stop(item->icon); @@ -226,13 +238,15 @@ static void menu_process_up(Menu* menu) { if(item && item->icon) { icon_animation_start(item->icon); } - return true; - }); + }, + true); } static void menu_process_down(Menu* menu) { with_view_model( - menu->view, (MenuModel * model) { + menu->view, + MenuModel * model, + { MenuItem* item = MenuItemArray_get(model->items, model->position); if(item && item->icon) { icon_animation_stop(item->icon); @@ -248,19 +262,21 @@ static void menu_process_down(Menu* menu) { if(item && item->icon) { icon_animation_start(item->icon); } - return true; - }); + }, + true); } static void menu_process_ok(Menu* menu) { MenuItem* item = NULL; with_view_model( - menu->view, (MenuModel * model) { + menu->view, + MenuModel * model, + { if(model->position < MenuItemArray_size(model->items)) { item = MenuItemArray_get(model->items, model->position); } - return true; - }); + }, + true); if(item && item->callback) { item->callback(item->callback_context, item->index); } diff --git a/applications/services/gui/modules/popup.c b/applications/services/gui/modules/popup.c index b3cb5e536..08e8d8c2b 100644 --- a/applications/services/gui/modules/popup.c +++ b/applications/services/gui/modules/popup.c @@ -124,7 +124,9 @@ Popup* popup_alloc() { view_set_exit_callback(popup->view, popup_stop_timer); with_view_model( - popup->view, (PopupModel * model) { + popup->view, + PopupModel * model, + { model->header.text = NULL; model->header.x = 0; model->header.y = 0; @@ -140,8 +142,8 @@ Popup* popup_alloc() { model->icon.x = 0; model->icon.y = 0; model->icon.icon = NULL; - return true; - }); + }, + true); return popup; } @@ -176,14 +178,16 @@ void popup_set_header( Align vertical) { furi_assert(popup); with_view_model( - popup->view, (PopupModel * model) { + popup->view, + PopupModel * model, + { model->header.text = text; model->header.x = x; model->header.y = y; model->header.horizontal = horizontal; model->header.vertical = vertical; - return true; - }); + }, + true); } void popup_set_text( @@ -195,25 +199,29 @@ void popup_set_text( Align vertical) { furi_assert(popup); with_view_model( - popup->view, (PopupModel * model) { + popup->view, + PopupModel * model, + { model->text.text = text; model->text.x = x; model->text.y = y; model->text.horizontal = horizontal; model->text.vertical = vertical; - return true; - }); + }, + true); } void popup_set_icon(Popup* popup, uint8_t x, uint8_t y, const Icon* icon) { furi_assert(popup); with_view_model( - popup->view, (PopupModel * model) { + popup->view, + PopupModel * model, + { model->icon.x = x; model->icon.y = y; model->icon.icon = icon; - return true; - }); + }, + true); } void popup_set_timeout(Popup* popup, uint32_t timeout_in_ms) { @@ -233,12 +241,14 @@ void popup_reset(Popup* popup) { furi_assert(popup); with_view_model( - popup->view, (PopupModel * model) { + popup->view, + PopupModel * model, + { memset(&model->header, 0, sizeof(model->header)); memset(&model->text, 0, sizeof(model->text)); memset(&model->icon, 0, sizeof(model->icon)); - return false; - }); + }, + false); popup->callback = NULL; popup->context = NULL; popup->timer_enabled = false; diff --git a/applications/services/gui/modules/submenu.c b/applications/services/gui/modules/submenu.c index 8d40d97b7..949598772 100644 --- a/applications/services/gui/modules/submenu.c +++ b/applications/services/gui/modules/submenu.c @@ -128,13 +128,15 @@ Submenu* submenu_alloc() { view_set_input_callback(submenu->view, submenu_view_input_callback); with_view_model( - submenu->view, (SubmenuModel * model) { + submenu->view, + SubmenuModel * model, + { SubmenuItemArray_init(model->items); model->position = 0; model->window_position = 0; model->header = NULL; - return true; - }); + }, + true); return submenu; } @@ -143,10 +145,7 @@ void submenu_free(Submenu* submenu) { furi_assert(submenu); with_view_model( - submenu->view, (SubmenuModel * model) { - SubmenuItemArray_clear(model->items); - return true; - }); + submenu->view, SubmenuModel * model, { SubmenuItemArray_clear(model->items); }, true); view_free(submenu->view); free(submenu); } @@ -167,32 +166,38 @@ void submenu_add_item( furi_assert(submenu); with_view_model( - submenu->view, (SubmenuModel * model) { + submenu->view, + SubmenuModel * model, + { item = SubmenuItemArray_push_new(model->items); item->label = label; item->index = index; item->callback = callback; item->callback_context = callback_context; - return true; - }); + }, + true); } void submenu_reset(Submenu* submenu) { furi_assert(submenu); with_view_model( - submenu->view, (SubmenuModel * model) { + submenu->view, + SubmenuModel * model, + { SubmenuItemArray_reset(model->items); model->position = 0; model->window_position = 0; model->header = NULL; - return true; - }); + }, + true); } void submenu_set_selected_item(Submenu* submenu, uint32_t index) { with_view_model( - submenu->view, (SubmenuModel * model) { + submenu->view, + SubmenuModel * model, + { uint32_t position = 0; SubmenuItemArray_it_t it; for(SubmenuItemArray_it(it, model->items); !SubmenuItemArray_end_p(it); @@ -225,14 +230,15 @@ void submenu_set_selected_item(Submenu* submenu, uint32_t index) { (SubmenuItemArray_size(model->items) - items_on_screen); } } - - return true; - }); + }, + true); } void submenu_process_up(Submenu* submenu) { with_view_model( - submenu->view, (SubmenuModel * model) { + submenu->view, + SubmenuModel * model, + { uint8_t items_on_screen = model->header ? 3 : 4; if(model->position > 0) { model->position--; @@ -246,13 +252,15 @@ void submenu_process_up(Submenu* submenu) { model->window_position = model->position - (items_on_screen - 1); } } - return true; - }); + }, + true); } void submenu_process_down(Submenu* submenu) { with_view_model( - submenu->view, (SubmenuModel * model) { + submenu->view, + SubmenuModel * model, + { uint8_t items_on_screen = model->header ? 3 : 4; if(model->position < (SubmenuItemArray_size(model->items) - 1)) { model->position++; @@ -265,20 +273,22 @@ void submenu_process_down(Submenu* submenu) { model->position = 0; model->window_position = 0; } - return true; - }); + }, + true); } void submenu_process_ok(Submenu* submenu) { SubmenuItem* item = NULL; with_view_model( - submenu->view, (SubmenuModel * model) { + submenu->view, + SubmenuModel * model, + { if(model->position < (SubmenuItemArray_size(model->items))) { item = SubmenuItemArray_get(model->items, model->position); } - return true; - }); + }, + true); if(item && item->callback) { item->callback(item->callback_context, item->index); @@ -289,8 +299,5 @@ void submenu_set_header(Submenu* submenu, const char* header) { furi_assert(submenu); with_view_model( - submenu->view, (SubmenuModel * model) { - model->header = header; - return true; - }); + submenu->view, SubmenuModel * model, { model->header = header; }, true); } diff --git a/applications/services/gui/modules/text_box.c b/applications/services/gui/modules/text_box.c index 65ee28301..99d7d04f1 100644 --- a/applications/services/gui/modules/text_box.c +++ b/applications/services/gui/modules/text_box.c @@ -21,20 +21,24 @@ typedef struct { static void text_box_process_down(TextBox* text_box) { with_view_model( - text_box->view, (TextBoxModel * model) { + text_box->view, + TextBoxModel * model, + { if(model->scroll_pos < model->scroll_num - 1) { model->scroll_pos++; // Search next line start while(*model->text_pos++ != '\n') ; } - return true; - }); + }, + true); } static void text_box_process_up(TextBox* text_box) { with_view_model( - text_box->view, (TextBoxModel * model) { + text_box->view, + TextBoxModel * model, + { if(model->scroll_pos > 0) { model->scroll_pos--; // Reach last symbol of previous line @@ -46,8 +50,8 @@ static void text_box_process_up(TextBox* text_box) { model->text_pos++; } } - return true; - }); + }, + true); } static void text_box_insert_endline(Canvas* canvas, TextBoxModel* model) { @@ -137,13 +141,15 @@ TextBox* text_box_alloc() { view_set_input_callback(text_box->view, text_box_view_input_callback); with_view_model( - text_box->view, (TextBoxModel * model) { + text_box->view, + TextBoxModel * model, + { model->text = NULL; model->text_formatted = furi_string_alloc_set(""); model->formatted = false; model->font = TextBoxFontText; - return true; - }); + }, + true); return text_box; } @@ -152,10 +158,7 @@ void text_box_free(TextBox* text_box) { furi_assert(text_box); with_view_model( - text_box->view, (TextBoxModel * model) { - furi_string_free(model->text_formatted); - return true; - }); + text_box->view, TextBoxModel * model, { furi_string_free(model->text_formatted); }, true); view_free(text_box->view); free(text_box); } @@ -169,13 +172,15 @@ void text_box_reset(TextBox* text_box) { furi_assert(text_box); with_view_model( - text_box->view, (TextBoxModel * model) { + text_box->view, + TextBoxModel * model, + { model->text = NULL; furi_string_set(model->text_formatted, ""); model->font = TextBoxFontText; model->focus = TextBoxFocusStart; - return true; - }); + }, + true); } void text_box_set_text(TextBox* text_box, const char* text) { @@ -183,31 +188,27 @@ void text_box_set_text(TextBox* text_box, const char* text) { furi_assert(text); with_view_model( - text_box->view, (TextBoxModel * model) { + text_box->view, + TextBoxModel * model, + { model->text = text; furi_string_reset(model->text_formatted); furi_string_reserve(model->text_formatted, strlen(text)); model->formatted = false; - return true; - }); + }, + true); } void text_box_set_font(TextBox* text_box, TextBoxFont font) { furi_assert(text_box); with_view_model( - text_box->view, (TextBoxModel * model) { - model->font = font; - return true; - }); + text_box->view, TextBoxModel * model, { model->font = font; }, true); } void text_box_set_focus(TextBox* text_box, TextBoxFocus focus) { furi_assert(text_box); with_view_model( - text_box->view, (TextBoxModel * model) { - model->focus = focus; - return true; - }); + text_box->view, TextBoxModel * model, { model->focus = focus; }, true); } diff --git a/applications/services/gui/modules/text_input.c b/applications/services/gui/modules/text_input.c index d7e00940d..79fa87728 100644 --- a/applications/services/gui/modules/text_input.c +++ b/applications/services/gui/modules/text_input.c @@ -429,10 +429,10 @@ void text_input_timer_callback(void* context) { TextInput* text_input = context; with_view_model( - text_input->view, (TextInputModel * model) { - model->valadator_message_visible = false; - return true; - }); + text_input->view, + TextInputModel * model, + { model->valadator_message_visible = false; }, + true); } TextInput* text_input_alloc() { @@ -446,10 +446,10 @@ TextInput* text_input_alloc() { text_input->timer = furi_timer_alloc(text_input_timer_callback, FuriTimerTypeOnce, text_input); with_view_model( - text_input->view, (TextInputModel * model) { - model->validator_text = furi_string_alloc(); - return false; - }); + text_input->view, + TextInputModel * model, + { model->validator_text = furi_string_alloc(); }, + false); text_input_reset(text_input); @@ -459,10 +459,10 @@ TextInput* text_input_alloc() { void text_input_free(TextInput* text_input) { furi_assert(text_input); with_view_model( - text_input->view, (TextInputModel * model) { - furi_string_free(model->validator_text); - return false; - }); + text_input->view, + TextInputModel * model, + { furi_string_free(model->validator_text); }, + false); // Send stop command furi_timer_stop(text_input->timer); @@ -477,7 +477,9 @@ void text_input_free(TextInput* text_input) { void text_input_reset(TextInput* text_input) { furi_assert(text_input); with_view_model( - text_input->view, (TextInputModel * model) { + text_input->view, + TextInputModel * model, + { model->text_buffer_size = 0; model->header = ""; model->selected_row = 0; @@ -491,8 +493,8 @@ void text_input_reset(TextInput* text_input) { model->validator_callback_context = NULL; furi_string_reset(model->validator_text); model->valadator_message_visible = false; - return true; - }); + }, + true); } View* text_input_get_view(TextInput* text_input) { @@ -508,7 +510,9 @@ void text_input_set_result_callback( size_t text_buffer_size, bool clear_default_text) { with_view_model( - text_input->view, (TextInputModel * model) { + text_input->view, + TextInputModel * model, + { model->callback = callback; model->callback_context = callback_context; model->text_buffer = text_buffer; @@ -519,8 +523,8 @@ void text_input_set_result_callback( model->selected_row = 2; model->selected_column = 8; } - return true; - }); + }, + true); } void text_input_set_validator( @@ -528,37 +532,36 @@ void text_input_set_validator( TextInputValidatorCallback callback, void* callback_context) { with_view_model( - text_input->view, (TextInputModel * model) { + text_input->view, + TextInputModel * model, + { model->validator_callback = callback; model->validator_callback_context = callback_context; - return true; - }); + }, + true); } TextInputValidatorCallback text_input_get_validator_callback(TextInput* text_input) { TextInputValidatorCallback validator_callback = NULL; with_view_model( - text_input->view, (TextInputModel * model) { - validator_callback = model->validator_callback; - return false; - }); + text_input->view, + TextInputModel * model, + { validator_callback = model->validator_callback; }, + false); return validator_callback; } void* text_input_get_validator_callback_context(TextInput* text_input) { void* validator_callback_context = NULL; with_view_model( - text_input->view, (TextInputModel * model) { - validator_callback_context = model->validator_callback_context; - return false; - }); + text_input->view, + TextInputModel * model, + { validator_callback_context = model->validator_callback_context; }, + false); return validator_callback_context; } void text_input_set_header_text(TextInput* text_input, const char* text) { with_view_model( - text_input->view, (TextInputModel * model) { - model->header = text; - return true; - }); + text_input->view, TextInputModel * model, { model->header = text; }, true); } diff --git a/applications/services/gui/modules/variable_item_list.c b/applications/services/gui/modules/variable_item_list.c index ec8fd3d20..acd46ee4b 100644 --- a/applications/services/gui/modules/variable_item_list.c +++ b/applications/services/gui/modules/variable_item_list.c @@ -92,7 +92,9 @@ static void variable_item_list_draw_callback(Canvas* canvas, void* _model) { void variable_item_list_set_selected_item(VariableItemList* variable_item_list, uint8_t index) { with_view_model( - variable_item_list->view, (VariableItemListModel * model) { + variable_item_list->view, + VariableItemListModel * model, + { uint8_t position = index; if(position >= VariableItemArray_size(model->items)) { position = 0; @@ -112,9 +114,8 @@ void variable_item_list_set_selected_item(VariableItemList* variable_item_list, model->window_position = (VariableItemArray_size(model->items) - 4); } } - - return true; - }); + }, + true); } uint8_t variable_item_list_get_selected_item_index(VariableItemList* variable_item_list) { @@ -181,7 +182,9 @@ static bool variable_item_list_input_callback(InputEvent* event, void* context) void variable_item_list_process_up(VariableItemList* variable_item_list) { with_view_model( - variable_item_list->view, (VariableItemListModel * model) { + variable_item_list->view, + VariableItemListModel * model, + { uint8_t items_on_screen = 4; if(model->position > 0) { model->position--; @@ -195,13 +198,15 @@ void variable_item_list_process_up(VariableItemList* variable_item_list) { model->window_position = model->position - (items_on_screen - 1); } } - return true; - }); + }, + true); } void variable_item_list_process_down(VariableItemList* variable_item_list) { with_view_model( - variable_item_list->view, (VariableItemListModel * model) { + variable_item_list->view, + VariableItemListModel * model, + { uint8_t items_on_screen = 4; if(model->position < (VariableItemArray_size(model->items) - 1)) { model->position++; @@ -214,8 +219,8 @@ void variable_item_list_process_down(VariableItemList* variable_item_list) { model->position = 0; model->window_position = 0; } - return true; - }); + }, + true); } VariableItem* variable_item_list_get_selected_item(VariableItemListModel* model) { @@ -239,7 +244,9 @@ VariableItem* variable_item_list_get_selected_item(VariableItemListModel* model) void variable_item_list_process_left(VariableItemList* variable_item_list) { with_view_model( - variable_item_list->view, (VariableItemListModel * model) { + variable_item_list->view, + VariableItemListModel * model, + { VariableItem* item = variable_item_list_get_selected_item(model); if(item->current_value_index > 0) { item->current_value_index--; @@ -247,13 +254,15 @@ void variable_item_list_process_left(VariableItemList* variable_item_list) { item->change_callback(item); } } - return true; - }); + }, + true); } void variable_item_list_process_right(VariableItemList* variable_item_list) { with_view_model( - variable_item_list->view, (VariableItemListModel * model) { + variable_item_list->view, + VariableItemListModel * model, + { VariableItem* item = variable_item_list_get_selected_item(model); if(item->current_value_index < (item->values_count - 1)) { item->current_value_index++; @@ -261,18 +270,20 @@ void variable_item_list_process_right(VariableItemList* variable_item_list) { item->change_callback(item); } } - return true; - }); + }, + true); } void variable_item_list_process_ok(VariableItemList* variable_item_list) { with_view_model( - variable_item_list->view, (VariableItemListModel * model) { + variable_item_list->view, + VariableItemListModel * model, + { if(variable_item_list->callback) { variable_item_list->callback(variable_item_list->context, model->position); } - return false; - }); + }, + false); } VariableItemList* variable_item_list_alloc() { @@ -285,12 +296,14 @@ VariableItemList* variable_item_list_alloc() { view_set_input_callback(variable_item_list->view, variable_item_list_input_callback); with_view_model( - variable_item_list->view, (VariableItemListModel * model) { + variable_item_list->view, + VariableItemListModel * model, + { VariableItemArray_init(model->items); model->position = 0; model->window_position = 0; - return true; - }); + }, + true); return variable_item_list; } @@ -299,15 +312,17 @@ void variable_item_list_free(VariableItemList* variable_item_list) { furi_assert(variable_item_list); with_view_model( - variable_item_list->view, (VariableItemListModel * model) { + variable_item_list->view, + VariableItemListModel * model, + { VariableItemArray_it_t it; for(VariableItemArray_it(it, model->items); !VariableItemArray_end_p(it); VariableItemArray_next(it)) { furi_string_free(VariableItemArray_ref(it)->current_value_text); } VariableItemArray_clear(model->items); - return false; - }); + }, + false); view_free(variable_item_list->view); free(variable_item_list); } @@ -316,15 +331,17 @@ void variable_item_list_reset(VariableItemList* variable_item_list) { furi_assert(variable_item_list); with_view_model( - variable_item_list->view, (VariableItemListModel * model) { + variable_item_list->view, + VariableItemListModel * model, + { VariableItemArray_it_t it; for(VariableItemArray_it(it, model->items); !VariableItemArray_end_p(it); VariableItemArray_next(it)) { furi_string_free(VariableItemArray_ref(it)->current_value_text); } VariableItemArray_reset(model->items); - return false; - }); + }, + false); } View* variable_item_list_get_view(VariableItemList* variable_item_list) { @@ -343,7 +360,9 @@ VariableItem* variable_item_list_add( furi_assert(variable_item_list); with_view_model( - variable_item_list->view, (VariableItemListModel * model) { + variable_item_list->view, + VariableItemListModel * model, + { item = VariableItemArray_push_new(model->items); item->label = label; item->values_count = values_count; @@ -351,8 +370,8 @@ VariableItem* variable_item_list_add( item->context = context; item->current_value_index = 0; item->current_value_text = furi_string_alloc(); - return true; - }); + }, + true); return item; } @@ -363,12 +382,14 @@ void variable_item_list_set_enter_callback( void* context) { furi_assert(callback); with_view_model( - variable_item_list->view, (VariableItemListModel * model) { + variable_item_list->view, + VariableItemListModel * model, + { UNUSED(model); variable_item_list->callback = callback; variable_item_list->context = context; - return false; - }); + }, + false); } void variable_item_set_current_value_index(VariableItem* item, uint8_t current_value_index) { diff --git a/applications/services/gui/modules/widget.c b/applications/services/gui/modules/widget.c index 802f76e24..6153b425b 100644 --- a/applications/services/gui/modules/widget.c +++ b/applications/services/gui/modules/widget.c @@ -36,7 +36,9 @@ static bool gui_widget_view_input_callback(InputEvent* event, void* context) { // Call all Widget Elements input handlers with_view_model( - widget->view, (GuiWidgetModel * model) { + widget->view, + GuiWidgetModel * model, + { ElementArray_it_t it; ElementArray_it(it, model->element); while(!ElementArray_end_p(it)) { @@ -46,8 +48,8 @@ static bool gui_widget_view_input_callback(InputEvent* event, void* context) { } ElementArray_next(it); } - return true; - }); + }, + true); return consumed; } @@ -61,10 +63,7 @@ Widget* widget_alloc() { view_set_input_callback(widget->view, gui_widget_view_input_callback); with_view_model( - widget->view, (GuiWidgetModel * model) { - ElementArray_init(model->element); - return true; - }); + widget->view, GuiWidgetModel * model, { ElementArray_init(model->element); }, true); return widget; } @@ -73,7 +72,9 @@ void widget_reset(Widget* widget) { furi_assert(widget); with_view_model( - widget->view, (GuiWidgetModel * model) { + widget->view, + GuiWidgetModel * model, + { ElementArray_it_t it; ElementArray_it(it, model->element); while(!ElementArray_end_p(it)) { @@ -83,8 +84,8 @@ void widget_reset(Widget* widget) { ElementArray_next(it); } ElementArray_reset(model->element); - return true; - }); + }, + true); } void widget_free(Widget* widget) { @@ -93,10 +94,7 @@ void widget_free(Widget* widget) { widget_reset(widget); // Free elements container with_view_model( - widget->view, (GuiWidgetModel * model) { - ElementArray_clear(model->element); - return true; - }); + widget->view, GuiWidgetModel * model, { ElementArray_clear(model->element); }, true); view_free(widget->view); free(widget); @@ -112,11 +110,13 @@ static void widget_add_element(Widget* widget, WidgetElement* element) { furi_assert(element); with_view_model( - widget->view, (GuiWidgetModel * model) { + widget->view, + GuiWidgetModel * model, + { element->parent = widget; ElementArray_push_back(model->element, element); - return true; - }); + }, + true); } void widget_add_string_multiline_element( diff --git a/applications/services/gui/view.h b/applications/services/gui/view.h index 5b4bf3609..b40f8ded5 100644 --- a/applications/services/gui/view.h +++ b/applications/services/gui/view.h @@ -211,25 +211,25 @@ void view_commit_model(View* view, bool update); #endif #ifdef __cplusplus -#define with_view_model_cpp(view, type, var, function_body) \ +#define with_view_model_cpp(view, type, var, code, update) \ { \ - type* p = static_cast(view_get_model(view)); \ - bool update = [&](type * var) function_body(p); \ + type var = static_cast(view_get_model(view)); \ + {code}; \ view_commit_model(view, update); \ } #else /** With clause for view model * * @param view View instance pointer - * @param function_body a (){} lambda declaration, executed within you - * parent function context + * @param type View model type + * @param code Code block that will be executed between model lock and unlock + * @param update Bool flag, if true, view will be updated after code block. Can be variable, so code block can decide if update is needed. * - * @return true if you want to emit view update, false otherwise */ -#define with_view_model(view, function_body) \ - { \ - void* p = view_get_model(view); \ - bool update = ({ bool __fn__ function_body __fn__; })(p); \ - view_commit_model(view, update); \ +#define with_view_model(view, type, code, update) \ + { \ + type = view_get_model(view); \ + {code}; \ + view_commit_model(view, update); \ } #endif diff --git a/applications/services/power/power_service/views/power_off.c b/applications/services/power/power_service/views/power_off.c index 398ebe4ab..b0046325c 100644 --- a/applications/services/power/power_service/views/power_off.c +++ b/applications/services/power/power_service/views/power_off.c @@ -87,19 +87,13 @@ View* power_off_get_view(PowerOff* power_off) { void power_off_set_time_left(PowerOff* power_off, uint8_t time_left) { furi_assert(power_off); with_view_model( - power_off->view, (PowerOffModel * model) { - model->time_left_sec = time_left; - return true; - }); + power_off->view, PowerOffModel * model, { model->time_left_sec = time_left; }, true); } PowerOffResponse power_off_get_response(PowerOff* power_off) { furi_assert(power_off); PowerOffResponse response; with_view_model( - power_off->view, (PowerOffModel * model) { - response = model->response; - return false; - }); + power_off->view, PowerOffModel * model, { response = model->response; }, false); return response; } diff --git a/applications/settings/about/about.c b/applications/settings/about/about.c index c14cf8a7f..3fe06bf8d 100644 --- a/applications/settings/about/about.c +++ b/applications/settings/about/about.c @@ -77,7 +77,7 @@ static DialogMessageButton unleashed_info_screen2(DialogsApp* dialogs, DialogMes const char* screen_text = "Custom plugins included\n" "For updates & info visit\n" - "github.com/Eng1n33r"; + "github.com/DarkFlippers"; dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop); result = dialog_message_show(dialogs, message); diff --git a/applications/settings/desktop_settings/desktop_settings_app.c b/applications/settings/desktop_settings/desktop_settings_app.c index a2ed8b724..afb5d59ec 100644 --- a/applications/settings/desktop_settings/desktop_settings_app.c +++ b/applications/settings/desktop_settings/desktop_settings_app.c @@ -22,6 +22,7 @@ DesktopSettingsApp* desktop_settings_app_alloc() { DesktopSettingsApp* app = malloc(sizeof(DesktopSettingsApp)); app->gui = furi_record_open(RECORD_GUI); + app->dialogs = furi_record_open(RECORD_DIALOGS); app->view_dispatcher = view_dispatcher_alloc(); app->scene_manager = scene_manager_alloc(&desktop_settings_scene_handlers, app); view_dispatcher_enable_queue(app->view_dispatcher); @@ -83,6 +84,7 @@ void desktop_settings_app_free(DesktopSettingsApp* app) { view_dispatcher_free(app->view_dispatcher); scene_manager_free(app->scene_manager); // Records + furi_record_close(RECORD_DIALOGS); furi_record_close(RECORD_GUI); free(app); } diff --git a/applications/settings/desktop_settings/desktop_settings_app.h b/applications/settings/desktop_settings/desktop_settings_app.h index 25c5b3adb..fc56c3253 100644 --- a/applications/settings/desktop_settings/desktop_settings_app.h +++ b/applications/settings/desktop_settings/desktop_settings_app.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,7 @@ typedef struct { DesktopSettings settings; Gui* gui; + DialogsApp* dialogs; SceneManager* scene_manager; ViewDispatcher* view_dispatcher; VariableItemList* variable_item_list; diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c index d8c579b3e..c7a964b1b 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -1,6 +1,28 @@ #include "../desktop_settings_app.h" #include "applications.h" #include "desktop_settings_scene.h" +#include +#include +#include + +static bool favorite_fap_selector_item_callback( + FuriString* file_path, + void* context, + uint8_t** icon_ptr, + FuriString* item_name) { + UNUSED(context); + Storage* storage = furi_record_open(RECORD_STORAGE); + bool success = fap_loader_load_name_and_icon(file_path, storage, icon_ptr, item_name); + furi_record_close(RECORD_STORAGE); + return success; +} + +static bool favorite_fap_selector_file_exists(char* file_path) { + Storage* storage = furi_record_open(RECORD_STORAGE); + bool exists = storage_file_exists(storage, file_path); + furi_record_close(RECORD_STORAGE); + return exists; +} static void desktop_settings_scene_favorite_submenu_callback(void* context, uint32_t index) { DesktopSettingsApp* app = context; @@ -12,6 +34,10 @@ void desktop_settings_scene_favorite_on_enter(void* context) { Submenu* submenu = app->submenu; submenu_reset(submenu); + uint32_t primary_favorite = + scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite); + uint32_t pre_select_item = 0; + for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { submenu_add_item( submenu, @@ -19,38 +45,95 @@ void desktop_settings_scene_favorite_on_enter(void* context) { i, desktop_settings_scene_favorite_submenu_callback, app); - } - uint32_t primary_favorite = - scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite); + if(primary_favorite) { // Select favorite item in submenu + if((app->settings.favorite_primary.is_external && + !strcmp(FLIPPER_APPS[i].name, FAP_LOADER_APP_NAME)) || + (!strcmp(FLIPPER_APPS[i].name, app->settings.favorite_primary.name_or_path))) { + pre_select_item = i; + } + } else { + if((app->settings.favorite_secondary.is_external && + !strcmp(FLIPPER_APPS[i].name, FAP_LOADER_APP_NAME)) || + (!strcmp(FLIPPER_APPS[i].name, app->settings.favorite_secondary.name_or_path))) { + pre_select_item = i; + } + } + } submenu_set_header( - app->submenu, primary_favorite ? "Primary favorite app:" : "Secondary favorite app:"); + submenu, primary_favorite ? "Primary favorite app:" : "Secondary favorite app:"); + submenu_set_selected_item(submenu, pre_select_item); // If set during loop, visual glitch. - if(primary_favorite) { - submenu_set_selected_item(app->submenu, app->settings.favorite_primary); - } else { - submenu_set_selected_item(app->submenu, app->settings.favorite_secondary); - } view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu); } bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent event) { DesktopSettingsApp* app = context; bool consumed = false; + FuriString* temp_path = furi_string_alloc_set_str(EXT_PATH("apps")); uint32_t primary_favorite = scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite); if(event.type == SceneManagerEventTypeCustom) { - if(primary_favorite) { - app->settings.favorite_primary = event.event; + if(strcmp(FLIPPER_APPS[event.event].name, FAP_LOADER_APP_NAME)) { + if(primary_favorite) { + app->settings.favorite_primary.is_external = false; + strncpy( + app->settings.favorite_primary.name_or_path, + FLIPPER_APPS[event.event].name, + MAX_APP_LENGTH); + } else { + app->settings.favorite_secondary.is_external = false; + strncpy( + app->settings.favorite_secondary.name_or_path, + FLIPPER_APPS[event.event].name, + MAX_APP_LENGTH); + } } else { - app->settings.favorite_secondary = event.event; + const DialogsFileBrowserOptions browser_options = { + .extension = ".fap", + .icon = &I_unknown_10px, + .skip_assets = true, + .hide_ext = true, + .item_loader_callback = favorite_fap_selector_item_callback, + .item_loader_context = app, + }; + + if(primary_favorite) { // Select favorite fap in file browser + if(favorite_fap_selector_file_exists( + app->settings.favorite_primary.name_or_path)) { + furi_string_set_str(temp_path, app->settings.favorite_primary.name_or_path); + } + } else { + if(favorite_fap_selector_file_exists( + app->settings.favorite_secondary.name_or_path)) { + furi_string_set_str(temp_path, app->settings.favorite_secondary.name_or_path); + } + } + + if(dialog_file_browser_show(app->dialogs, temp_path, temp_path, &browser_options)) { + if(primary_favorite) { + app->settings.favorite_primary.is_external = true; + strncpy( + app->settings.favorite_primary.name_or_path, + furi_string_get_cstr(temp_path), + MAX_APP_LENGTH); + } else { + app->settings.favorite_secondary.is_external = true; + strncpy( + app->settings.favorite_secondary.name_or_path, + furi_string_get_cstr(temp_path), + MAX_APP_LENGTH); + } + } } scene_manager_previous_scene(app->scene_manager); consumed = true; } + + furi_string_free(temp_path); return consumed; } diff --git a/applications/settings/power_settings_app/views/battery_info.c b/applications/settings/power_settings_app/views/battery_info.c index aa3a1e962..1a8bc71ec 100644 --- a/applications/settings/power_settings_app/views/battery_info.c +++ b/applications/settings/power_settings_app/views/battery_info.c @@ -119,8 +119,8 @@ void battery_info_set_data(BatteryInfo* battery_info, BatteryInfoModel* data) { furi_assert(battery_info); furi_assert(data); with_view_model( - battery_info->view, (BatteryInfoModel * model) { - memcpy(model, data, sizeof(BatteryInfoModel)); - return true; - }); + battery_info->view, + BatteryInfoModel * model, + { memcpy(model, data, sizeof(BatteryInfoModel)); }, + true); } diff --git a/applications/system/updater/views/updater_main.c b/applications/system/updater/views/updater_main.c index 8d6694d89..5ed3c70aa 100644 --- a/applications/system/updater/views/updater_main.c +++ b/applications/system/updater/views/updater_main.c @@ -28,22 +28,25 @@ void updater_main_model_set_state( const char* message, uint8_t progress, bool failed) { + bool update = false; with_view_model( - main_view->view, (UpdaterProgressModel * model) { + main_view->view, + UpdaterProgressModel * model, + { model->failed = failed; model->progress = progress; if(furi_string_cmp_str(model->status, message)) { furi_string_set(model->status, message); model->rendered_progress = progress; - return true; - } - if((model->rendered_progress > progress) || - ((progress - model->rendered_progress) > PROGRESS_RENDER_STEP)) { + update = true; + } else if( + (model->rendered_progress > progress) || + ((progress - model->rendered_progress) > PROGRESS_RENDER_STEP)) { model->rendered_progress = progress; - return true; + update = true; } - return false; - }); + }, + update); } View* updater_main_get_view(UpdaterMainView* main_view) { @@ -104,10 +107,10 @@ UpdaterMainView* updater_main_alloc() { view_allocate_model(main_view->view, ViewModelTypeLocking, sizeof(UpdaterProgressModel)); with_view_model( - main_view->view, (UpdaterProgressModel * model) { - model->status = furi_string_alloc_set("Waiting for SD card"); - return true; - }); + main_view->view, + UpdaterProgressModel * model, + { model->status = furi_string_alloc_set("Waiting for SD card"); }, + true); view_set_context(main_view->view, main_view); view_set_input_callback(main_view->view, updater_main_input); @@ -119,10 +122,7 @@ UpdaterMainView* updater_main_alloc() { void updater_main_free(UpdaterMainView* main_view) { furi_assert(main_view); with_view_model( - main_view->view, (UpdaterProgressModel * model) { - furi_string_free(model->status); - return false; - }); + main_view->view, UpdaterProgressModel * model, { furi_string_free(model->status); }, false); view_free(main_view->view); free(main_view); } diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index 54384cf40..fe8992907 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,7 +1,13 @@ Filetype: IR library file Version: 1 -# Last Updated 28th Sept, 2022 +# Last Updated 9th Oct, 2022 # +# ON +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3305 1598 432 411 413 404 410 1198 440 403 411 1197 441 402 412 405 409 408 406 1202 436 1198 440 403 411 406 408 409 405 1229 409 1199 439 404 410 407 407 410 414 403 411 406 408 409 405 412 412 405 409 408 406 411 413 404 410 407 407 410 414 1219 409 409 405 412 412 405 409 408 406 411 413 404 410 407 407 1226 412 405 409 409 405 412 412 405 409 1224 414 1194 434 1201 437 1196 432 1203 435 1198 440 1194 434 1200 438 378 436 408 406 1228 410 381 433 410 414 403 411 406 408 409 405 412 412 405 409 408 406 1228 410 1198 440 403 411 406 408 1199 439 405 409 408 406 411 413 1221 407 410 414 1219 409 409 405 1202 436 1199 439 403 411 406 408 410 414 402 412 405 409 408 406 411 413 404 410 407 407 410 414 403 411 406 408 409 405 412 412 405 409 408 406 411 413 404 410 407 407 410 414 403 411 406 408 409 405 412 412 404 410 408 406 411 413 403 411 407 407 410 414 402 412 405 409 408 406 411 413 404 410 407 407 410 414 403 411 406 408 409 405 412 412 405 409 408 406 1202 436 407 407 410 414 403 411 406 408 1200 438 1195 433 1202 436 406 408 1201 437 405 409 # SWING ON name: SWING type: raw @@ -260,7 +266,7 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 5626 5579 569 549 562 582 539 581 540 578 543 577 544 575 536 1702 541 1703 540 549 562 557 564 1700 543 1670 563 1677 566 1698 545 547 564 586 535 1674 569 550 571 1668 565 1674 569 578 543 550 571 1670 563 587 545 1665 568 1671 562 1677 566 1700 543 577 544 548 563 1704 539 557 564 1698 545 574 537 1677 566 552 569 577 544 1668 565 554 567 583 538 1670 563 1702 541 1671 572 547 564 583 538 553 568 552 569 1700 543 545 566 582 539 1698 535 558 563 557 564 554 567 1671 562 585 536 -# +# ON name: POWER type: raw frequency: 38000 @@ -783,12 +789,6 @@ protocol: NECext address: 08 F5 00 00 command: 00 FF 00 00 # -name: POWER -type: raw -frequency: 38000 -duty_cycle: 0.330000 -data: 3302 1618 435 393 436 391 438 1207 431 396 433 1213 435 392 437 391 438 388 441 1206 432 1214 434 392 437 389 440 388 431 1215 433 1213 435 392 437 390 439 388 431 396 433 395 434 392 437 390 439 388 431 396 433 394 435 392 437 390 439 388 441 1205 433 395 434 392 437 389 440 388 431 396 433 394 435 392 437 1209 439 388 431 397 432 394 435 393 436 1210 438 387 432 396 433 394 435 392 437 390 439 388 431 1215 433 394 435 1211 437 1208 440 1205 433 1213 435 1211 437 1209 439 -# name: TIMER type: raw frequency: 38000 @@ -1274,4 +1274,16 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 3157 1552 601 1065 575 1093 598 330 554 330 530 340 545 1094 573 338 545 341 545 1094 572 1095 572 340 544 1097 570 342 543 341 543 1101 567 1123 543 342 542 1124 543 1124 543 344 542 342 542 1125 542 344 542 345 541 1125 541 344 542 344 542 344 542 344 542 344 542 343 541 344 541 345 541 344 542 344 542 344 541 345 541 343 541 344 542 344 541 344 542 344 541 1126 542 344 542 344 541 1126 542 344 542 345 541 1126 541 1126 541 345 541 343 541 345 541 345 541 344 542 344 541 1127 541 1126 541 1125 541 1127 541 345 541 344 541 344 541 344 541 1126 541 344 541 1126 542 344 541 344 541 344 541 344 542 344 542 343 541 345 541 345 541 344 542 344 542 345 540 343 541 344 541 344 541 344 542 344 541 344 541 344 542 343 541 344 542 344 541 345 541 345 541 344 542 344 541 343 541 344 542 344 542 344 542 344 542 344 542 344 542 343 541 344 542 344 542 345 541 344 542 345 541 345 541 343 542 345 542 1127 541 344 541 1126 542 344 542 +# OFF +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3306 1624 406 411 413 404 410 1224 414 403 411 1223 405 412 412 405 409 408 406 1228 410 1224 414 402 412 406 408 409 405 1229 409 1224 414 403 411 407 407 410 414 402 412 406 408 409 405 412 412 404 410 408 406 411 413 403 411 406 408 409 405 1230 408 408 406 411 413 404 410 407 407 410 414 403 411 406 408 1226 412 405 409 408 406 411 413 404 410 1224 414 403 411 406 408 409 405 412 412 405 409 408 406 1228 410 407 407 1227 411 1222 406 1229 409 1198 440 1220 408 1227 411 +# OFF +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 3302 1618 435 393 436 391 438 1207 431 396 433 1213 435 392 437 391 438 388 441 1206 432 1214 434 392 437 389 440 388 431 1215 433 1213 435 392 437 390 439 388 431 396 433 395 434 392 437 390 439 388 431 396 433 394 435 392 437 390 439 388 441 1205 433 395 434 392 437 389 440 388 431 396 433 394 435 392 437 1209 439 388 431 397 432 394 435 393 436 1210 438 387 432 396 433 394 435 392 437 390 439 388 431 1215 433 394 435 1211 437 1208 440 1205 433 1213 435 1211 437 1209 439 # diff --git a/assets/slideshow/update_default/frame_02.png b/assets/slideshow/update_default/frame_02.png index fcb7cd396..db9710922 100644 Binary files a/assets/slideshow/update_default/frame_02.png and b/assets/slideshow/update_default/frame_02.png differ diff --git a/documentation/AppsOnSDCard.md b/documentation/AppsOnSDCard.md index 552be13e4..aff8314dc 100644 --- a/documentation/AppsOnSDCard.md +++ b/documentation/AppsOnSDCard.md @@ -13,7 +13,7 @@ FAPs are created and developed the same way as internal applications that are pa To build your application as a FAP, just create a folder with your app's source code in `applications_user`, then write its code the way you'd do when creating a regular built-in application. Then configure its `application.fam` manifest — and set its *apptype* to FlipperAppType.EXTERNAL. See [Application Manifests](./AppManifests.md#application-definition) for more details. - * To build your application, run `./fbt firmware_{APPID}`, where APPID is your application's ID in its manifest. + * To build your application, run `./fbt fap_{APPID}`, where APPID is your application's ID in its manifest. * To build your app, then upload it over USB & run it on Flipper, use `./fbt launch_app APPSRC=applications/path/to/app`. This command is configured in default [VSCode profile](../.vscode/ReadMe.md) as "Launch App on Flipper" build action (Ctrl+Shift+B menu). * To build all FAPs, run `./fbt plugin_dist`. diff --git a/documentation/CustomFlipperName.md b/documentation/CustomFlipperName.md index 244c8acc9..4dfc42246 100644 --- a/documentation/CustomFlipperName.md +++ b/documentation/CustomFlipperName.md @@ -1,7 +1,7 @@ # How to change Flipper name: ## Instruction -1. Read [How to build](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToBuild.md) and [How to install](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/HowToInstall.md) to know how to build and install firmware +1. Read [How to build](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToBuild.md) and [How to install](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/HowToInstall.md) to know how to build and install firmware 2. Follow how to build instructions to prepare all things before continuing 3. Run release build to verify all is ok - `./fbt COMPACT=1 DEBUG=0 updater_package` 4. Clear build files - `./fbt COMPACT=1 DEBUG=0 updater_package -c` diff --git a/documentation/HowToBuild.md b/documentation/HowToBuild.md index be3d87763..92bd4e418 100644 --- a/documentation/HowToBuild.md +++ b/documentation/HowToBuild.md @@ -14,7 +14,7 @@ For development: You should clone with ```shell -$ git clone --recursive https://github.com/Eng1n33r/flipperzero-firmware.git +$ git clone --recursive https://github.com/DarkFlippers/unleashed-firmware.git ``` # Build on Linux/macOS diff --git a/documentation/HowToInstall.md b/documentation/HowToInstall.md index 718b0f717..fb9f6eb24 100644 --- a/documentation/HowToInstall.md +++ b/documentation/HowToInstall.md @@ -1,7 +1,7 @@ # Update firmware -## [Get Latest Firmware from GitHub Releases](https://github.com/Eng1n33r/flipperzero-firmware/releases) +## [Get Latest Firmware from GitHub Releases](https://github.com/DarkFlippers/unleashed-firmware/releases)

@@ -14,7 +14,7 @@ ## With Web Updater - Be sure you updated to latest official release before(if installing for the first time), and verify that microSD card is installed -- Open latest release page - [Releases](https://github.com/Eng1n33r/flipperzero-firmware/releases/latest) +- Open latest release page - [Releases](https://github.com/DarkFlippers/unleashed-firmware/releases/latest) - Connect your device and select `Install via Web Updater` after that on web updater page - press `Connect` button - Press `Install` button @@ -31,7 +31,7 @@ after that on web updater page - press `Connect` button ## With iOS mobile app - Be sure you updated to latest official release before(if installing for the first time), and verify that microSD card is installed -- Open latest release page - [Releases](https://github.com/Eng1n33r/flipperzero-firmware/releases/latest) +- Open latest release page - [Releases](https://github.com/DarkFlippers/unleashed-firmware/releases/latest) - Download `flipper-z-f7-update-(version).tgz` - Open downloads in ios Files app, select downloaded `.tgz` file, click Share, select Flipper App - In flipper app click green `Update` button, be sure it shows `Custom flipper-z-f7-update...` in Update Channel @@ -45,11 +45,11 @@ after that on web updater page - press `Connect` button

-## With qFlipper (1.2.0) +## With qFlipper (1.2.0+) -- Download qFlipper that allows `.tgz` installation [Download qFlipper 1.2.0 (official link)](https://update.flipperzero.one/builds/qFlipper/1.2.0/) +- Download qFlipper that allows `.tgz` installation [Download qFlipper 1.2.1 (official link)](https://update.flipperzero.one/builds/qFlipper/1.2.1/) - Be sure you updated to latest official release before(only if installing for the first time), and verify that microSD card is installed -- Open latest release page - [Releases](https://github.com/Eng1n33r/flipperzero-firmware/releases/latest) +- Open latest release page - [Releases](https://github.com/DarkFlippers/unleashed-firmware/releases/latest) - Download `flipper-z-f7-update-(version).tgz` - Launch qFlipper - Connect your device and select `Install from file` @@ -84,6 +84,6 @@ after that on web updater page - press `Connect` button # After install: -- ## [Read instructions how to use plugins and more](https://github.com/Eng1n33r/flipperzero-firmware#instructions) +- ## [Read instructions how to use plugins and more](https://github.com/DarkFlippers/unleashed-firmware#instructions) -- ## [How To: Configure Sub-GHz Remote App](https://github.com/Eng1n33r/flipperzero-firmware/blob/dev/documentation/SubGHzRemotePlugin.md) +- ## [How To: Configure Sub-GHz Remote App](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemotePlugin.md) diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index 388f64d37..3fe57162f 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -521,7 +521,7 @@ static SectionType elf_preload_section( // TODO: how to do it not by name? // .ARM: type 0x70000001, flags SHF_ALLOC | SHF_LINK_ORDER // .rel.ARM: type 0x9, flags SHT_REL - if(str_prefix(name, ".ARM") || str_prefix(name, ".rel.ARM")) { + if(str_prefix(name, ".ARM.") || str_prefix(name, ".rel.ARM.")) { FURI_LOG_D(TAG, "Ignoring ARM section"); return SectionTypeUnused; } diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index 575124df6..bd5104285 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -79,7 +79,7 @@ void* subghz_protocol_encoder_came_atomo_alloc(SubGhzEnvironment* environment) { instance->generic.protocol_name = instance->base.protocol->name; instance->encoder.repeat = 10; - instance->encoder.size_upload = 1024; //actual size about 760 + instance->encoder.size_upload = 900; //actual size 766+ instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance; diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index 78212298c..766b5f401 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -96,7 +96,7 @@ void* subghz_protocol_encoder_nice_flor_s_alloc(SubGhzEnvironment* environment) TAG, "Loading rainbow table from %s", instance->nice_flor_s_rainbow_table_file_name); } instance->encoder.repeat = 10; - instance->encoder.size_upload = 1800; //wrong!! upload 186*16 = 2976 - actual size about 1716 + instance->encoder.size_upload = 1728; //wrong!! upload 186*16 = 2976 - actual size about 1728 instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration)); instance->encoder.is_running = false; return instance;