From a934c70a001580e9c6d08b7df3b7c94bd17ed902 Mon Sep 17 00:00:00 2001 From: WillyJL Date: Tue, 22 Jul 2025 15:03:15 +0200 Subject: [PATCH 1/2] JS: Expose button event type in gui/widget button callback --nobuild --- CHANGELOG.md | 1 + .../examples/apps/Scripts/Examples/gui.js | 4 +- .../system/js_app/modules/js_gui/widget.c | 53 ++++++++++++++----- .../js_app/packages/fz-sdk/gui/widget.d.ts | 6 ++- documentation/js/js_gui__widget.md | 17 ++++++ 5 files changed, 65 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbf7cecb2..22438f80e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - Sub-GHz: - UL: Add 868.46 MHz to default subghz freqs list (by @xMasterX) - UL: Reduce less popular freqs in default hopper preset, make it faster (by @xMasterX) +- JS: Expose button event type in `gui/widget` button callback (by @WillyJL) - UL: Docs: Update Sub-GHz DoorHan programming instructions (by @li0ard) ### Fixed: diff --git a/applications/system/js_app/examples/apps/Scripts/Examples/gui.js b/applications/system/js_app/examples/apps/Scripts/Examples/gui.js index d33de988f..9b7042848 100644 --- a/applications/system/js_app/examples/apps/Scripts/Examples/gui.js +++ b/applications/system/js_app/examples/apps/Scripts/Examples/gui.js @@ -137,8 +137,8 @@ eventLoop.subscribe(gui.viewDispatcher.navigation, function (_sub, _, gui, views }, gui, views, eventLoop); // go to the demo chooser screen when the right key is pressed on the widget screen -eventLoop.subscribe(views.stopwatchWidget.button, function (_sub, buttonId, gui, views) { - if (buttonId === "right") +eventLoop.subscribe(views.stopwatchWidget.button, function (_sub, buttonEvent, gui, views) { + if (buttonEvent.key === "right" && buttonEvent.type === "short") gui.viewDispatcher.switchTo(views.demos); }, gui, views); diff --git a/applications/system/js_app/modules/js_gui/widget.c b/applications/system/js_app/modules/js_gui/widget.c index bb2898030..47149b4ac 100644 --- a/applications/system/js_app/modules/js_gui/widget.c +++ b/applications/system/js_app/modules/js_gui/widget.c @@ -10,6 +10,11 @@ typedef struct { #define QUEUE_LEN 2 +typedef struct { + GuiButtonType key; + InputType type; +} JsWidgetButtonEvent; + /** * @brief Parses position (X and Y) from an element declaration object */ @@ -101,8 +106,11 @@ static bool element_get_text(struct mjs* mjs, mjs_val_t element, mjs_val_t* text * @brief Widget button element callback */ static void js_widget_button_callback(GuiButtonType result, InputType type, JsWidgetCtx* context) { - UNUSED(type); - furi_check(furi_message_queue_put(context->queue, &result, 0) == FuriStatusOk); + JsWidgetButtonEvent event = { + .key = result, + .type = type, + }; + furi_check(furi_message_queue_put(context->queue, &event, 0) == FuriStatusOk); } #define DESTRUCTURE_OR_RETURN(mjs, child_obj, part, ...) \ @@ -263,25 +271,44 @@ static mjs_val_t js_widget_button_event_transformer( FuriMessageQueue* queue, JsWidgetCtx* context) { UNUSED(context); - GuiButtonType btn_type; - furi_check(furi_message_queue_get(queue, &btn_type, 0) == FuriStatusOk); - const char* btn_name; - if(btn_type == GuiButtonTypeLeft) { - btn_name = "left"; - } else if(btn_type == GuiButtonTypeCenter) { - btn_name = "center"; - } else if(btn_type == GuiButtonTypeRight) { - btn_name = "right"; + JsWidgetButtonEvent event; + furi_check(furi_message_queue_get(queue, &event, 0) == FuriStatusOk); + const char* event_key; + if(event.key == GuiButtonTypeLeft) { + event_key = "left"; + } else if(event.key == GuiButtonTypeCenter) { + event_key = "center"; + } else if(event.key == GuiButtonTypeRight) { + event_key = "right"; } else { furi_crash(); } - return mjs_mk_string(mjs, btn_name, ~0, false); + const char* event_type; + if(event.type == InputTypePress) { + event_type = "press"; + } else if(event.type == InputTypeRelease) { + event_type = "release"; + } else if(event.type == InputTypeShort) { + event_type = "short"; + } else if(event.type == InputTypeLong) { + event_type = "long"; + } else if(event.type == InputTypeRepeat) { + event_type = "repeat"; + } else { + furi_crash(); + } + mjs_val_t obj = mjs_mk_object(mjs); + JS_ASSIGN_MULTI(mjs, obj) { + JS_FIELD("key", mjs_mk_string(mjs, event_key, ~0, true)); + JS_FIELD("type", mjs_mk_string(mjs, event_type, ~0, true)); + } + return obj; } static void* js_widget_custom_make(struct mjs* mjs, Widget* widget, mjs_val_t view_obj) { UNUSED(widget); JsWidgetCtx* context = malloc(sizeof(JsWidgetCtx)); - context->queue = furi_message_queue_alloc(QUEUE_LEN, sizeof(GuiButtonType)); + context->queue = furi_message_queue_alloc(QUEUE_LEN, sizeof(JsWidgetButtonEvent)); context->contract = (JsEventLoopContract){ .magic = JsForeignMagic_JsEventLoopContract, .object_type = JsEventLoopObjectTypeQueue, diff --git a/applications/system/js_app/packages/fz-sdk/gui/widget.d.ts b/applications/system/js_app/packages/fz-sdk/gui/widget.d.ts index bf4aab22b..c524c53cb 100644 --- a/applications/system/js_app/packages/fz-sdk/gui/widget.d.ts +++ b/applications/system/js_app/packages/fz-sdk/gui/widget.d.ts @@ -58,12 +58,16 @@ type Element = StringMultilineElement type Props = {}; type Child = Element; +declare class ButtonEvent { + key: "left" | "center" | "right"; + type: "press" | "release" | "short" | "long" | "repeat"; +} declare class Widget extends View { /** * Event source for buttons. Only gets fired if there's a corresponding * button element. */ - button: Contract<"left" | "center" | "right">; + button: Contract; } declare class WidgetFactory extends ViewFactory { } declare const factory: WidgetFactory; diff --git a/documentation/js/js_gui__widget.md b/documentation/js/js_gui__widget.md index 9ea3e4dfa..4c922a67c 100644 --- a/documentation/js/js_gui__widget.md +++ b/documentation/js/js_gui__widget.md @@ -35,3 +35,20 @@ Elements are objects with properties to define them, in the form `{ element: "ty | `rect` | `x` (number), `y` (number)
`w` (number), `h` (number)
`radius` (number), `fill` (boolean) | Draw a rectangle, optionally rounded and filled. | | `circle` | `x` (number), `y` (number)
`radius` (number), `fill` (boolean) | Draw a circle, optionally filled. | | `line` | `x1` (number), `y1` (number)
`x2` (number), `y2` (number) | Draw a line between 2 points. | + +## Structures + +### ButtonEvent + +Button event information structure. + +**Fields** + +- key: The key that was pressed (`"left" | "center" | "right"`) +- type: The type of the event (`"press" | "release" | "short" | "long" | "repeat"`) + +## View events + +| Item | Type | Description | +|----------|--------|-----------------------------------------------------------------------------| +| `button` | `ButtonEvent`| Fires when the user presses on one of the three possible buttons if there's a corresponding button element. Refer to the `ButtonEvent` structure above for possible values. | From 580211c97c026a2aa422a2a8aa46aed94093ddbb Mon Sep 17 00:00:00 2001 From: WillyJL Date: Tue, 22 Jul 2025 17:10:41 +0200 Subject: [PATCH 2/2] CLI: Fix long delay with quick connect/disconnect noticeable with qflipper, for some reason it sets DTR on/off/on again so flipper starts CLI, stops it, then starts again but cli shell is trying to print motd, and pipe is already broken so each character of motd times out for 100ms changing pipe timeout to 10ms works too, but is just a workaround it didnt always happen, i think that variable time of loading ext cmds made it so on ofw it usually manages to print motd before pipe is broken on cfw with more ext commands it always hung, on ofw only sometimes important part is bailing early in cli shell in cli vcp i made it cleanup cli shell on disconnect so it doesnt stay around after disconnecting usb, might free a little ram maybe --- CHANGELOG.md | 1 + applications/services/cli/cli_vcp.c | 14 +++++--------- lib/toolbox/cli/shell/cli_shell.c | 5 +++++ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22438f80e..f9bf5f5ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - UL: Docs: Update Sub-GHz DoorHan programming instructions (by @li0ard) ### Fixed: +- CLI: Fix long delay with quick connect/disconnect, qFlipper should connect faster as expected again (by @WillyJL) - Bad KB: Fix modifier keys with HOLD/RELEASE commands (by @WillyJL) - Desktop: Fix lock screen hang (#438 by @aaronjamt) - NFC: Fix incorrect Saflok year formula (#433 by @Eltrick) diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index f65722241..6a8afe184 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -217,7 +217,11 @@ static void cli_vcp_internal_event_happened(FuriEventLoopObject* object, void* c // disconnect our side of the pipe pipe_detach_from_event_loop(cli_vcp->own_pipe); pipe_free(cli_vcp->own_pipe); - cli_vcp->own_pipe = NULL; + + // wait for shell to stop + cli_shell_join(cli_vcp->shell); + cli_shell_free(cli_vcp->shell); + pipe_free(cli_vcp->shell_pipe); break; } @@ -226,14 +230,6 @@ static void cli_vcp_internal_event_happened(FuriEventLoopObject* object, void* c FURI_LOG_D(TAG, "Connected"); cli_vcp->is_connected = true; - // wait for previous shell to stop - furi_check(!cli_vcp->own_pipe); - if(cli_vcp->shell) { - cli_shell_join(cli_vcp->shell); - cli_shell_free(cli_vcp->shell); - pipe_free(cli_vcp->shell_pipe); - } - // start shell thread PipeSideBundle bundle = pipe_alloc(VCP_BUF_SIZE, 1); cli_vcp->own_pipe = bundle.alices_side; diff --git a/lib/toolbox/cli/shell/cli_shell.c b/lib/toolbox/cli/shell/cli_shell.c index 8663577e3..05aecc444 100644 --- a/lib/toolbox/cli/shell/cli_shell.c +++ b/lib/toolbox/cli/shell/cli_shell.c @@ -469,11 +469,16 @@ static int32_t cli_shell_thread(void* context) { cli_shell_init(shell); FURI_LOG_D(TAG, "Started"); + if(pipe_state(shell->pipe) == PipeStateBroken) goto bail; + shell->motd(shell->callback_context); cli_shell_line_prompt(shell->components[CliShellComponentLine]); + if(pipe_state(shell->pipe) == PipeStateBroken) goto bail; + furi_event_loop_run(shell->event_loop); +bail: FURI_LOG_D(TAG, "Stopped"); cli_shell_deinit(shell); return 0;