资讯动态

Flipper Zero JS SDK 实战:深入解析 gui/text_input 文本输入键盘视图

发布时间:2026/9/14 22:40:30 来源:尧图企业网站定制
Flipper Zero JS SDK 实战深入解析 gui/text_input 文本输入键盘视图【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware本文围绕 Flipper Zero 固件 JS SDK 中的gui/text_input模块展开讲解如何在 JS 应用中创建文本输入键盘、配置其全部属性header、minLength、maxLength、defaultText、defaultTextClear并订阅input事件获取用户输入。读完本文你将掌握该视图的完整用法并能从源码层面理解 JS 属性如何映射到底层 C 视图以及输入结果如何通过事件循环event loop的合约Contract机制异步交付给 JS 回调。模块概览与依赖顺序gui/text_input是 JS SDK 中用于显示一个文本键盘的视图模块。它允许用户在设备上通过物理按键逐字符输入一段文本例如设备改名、问卷采集等场景并在用户按下 Save 且文本长度合法后通过事件将整段文本交给 JS 代码处理。标准引入方式为let eventLoop require(event_loop); let gui require(gui); let textInputView require(gui/text_input);官方文档特别强调gui/text_input依赖gui模块而gui又依赖event_loop模块因此三者必须按上述顺序引入event_loop最先gui/text_input最后。建议先理解event_loop与gui两个基础模块的概念再使用本视图。这一点在 SDK 类型声明文件 text_input.d.ts 的头部注释中同样有说明该声明还指出此模块自 JS SDK 0.1 起可用。完整示例gui.js 中的键盘视图用法官方示例脚本 gui.js 演示了 JS SDK 全部 GUI 视图其中Text input Dialog演示完整展示了本模块的用法。核心代码分三步第一步创建视图实例并设置属性let views { keyboard: textInputView.makeWith({ header: Enter your name, minLength: 0, maxLength: 32, defaultText: flipper.getName(), defaultTextClear: true, }), // ... 其他视图 helloDialog: dialogView.make(), };这里makeWith({...})传入的属性对象就是下文View props一节描述的全部参数。注意defaultText: flipper.getName()——它借用flipper模块拿到设备当前名字作为键盘的初始显示文本defaultTextClear: true表示用户一旦开始打字预填文本就会被清空而不是追加这是改设备名这类场景最自然的交互方式。第二步将视图加入调度器在演示菜单回调中选中Text input Dialog时执行gui.viewDispatcher.switchTo(views.keyboard);viewDispatcher负责管理当前屏幕上显示哪个视图switchTo是切换到新视图的唯一入口视图切换完成后由事件循环继续驱动交互。第三步订阅 input 事件处理用户输入// say hi after keyboard input eventLoop.subscribe(views.keyboard.input, function (_sub, name, gui, views) { views.keyboard.set(defaultText, name); // Remember for next usage views.helloDialog.set(text, Hi name ! :)); views.helloDialog.set(center, Hi Flipper! :)); gui.viewDispatcher.switchTo(views.helloDialog); }, gui, views);这段订阅逻辑值得注意的细节views.keyboard.input是一个事件合约ContracteventLoop.subscribe的第二个参数是订阅回调回调的第二个实参name即用户输入的字符串views.keyboard.set(defaultText, name)把本次输入回写为键盘的默认文本——官方注释写明Remember for next usage即下次打开键盘时直接显示上次输入的名字避免重复输入随后切换到helloDialog对话框展示问候语对话框center按钮的事件又由另一个订阅者接管把流程切回演示菜单形成一个完整的输入—反馈闭环。示例中同样存在统一的导航处理按下 Back 键时订阅gui.viewDispatcher.navigation若非停留在顶层菜单则切回views.demos。这与text_input本身无关但属于 GUI 应用的标准导航模式实际开发时可一并参考 gui.js。View props属性全表与源码级语义视图通过makeWith初始创建时传入属性也可在运行中用view.set(prop, value)更新。官方文档给出的属性表如下与 SDK 声明完全一致PropType说明minLengthnumber允许的最短文本长度maxLengthnumber允许的最长文本长度默认32headerstring显示在键盘上方的单行提示文本defaultTextstring键盘打开时默认显示的文本defaultTextClearboolean用户键入下一个字符时是否清空默认文本源码印证JsViewDescriptor 与五个属性解析器JS 侧的属性与 C 侧视图之间的桥梁是 text_input.c。文件末尾的JsViewDescriptor声明了prop_cnt 5以及五个属性解析器与上表一一对应static const JsViewDescriptor view_descriptor { .alloc (JsViewAlloc)text_input_alloc, .free (JsViewFree)text_input_free, .get_view (JsViewGetView)text_input_get_view, .custom_make (JsViewCustomMake)ctx_make, .custom_destroy (JsViewCustomDestroy)ctx_destroy, .prop_cnt 5, .props { (JsViewPropDescriptor){ .name header, .type JsViewPropTypeString, .assign (JsViewPropAssign)header_assign }, (JsViewPropDescriptor){ .name minLength, .type JsViewPropTypeNumber, .assign (JsViewPropAssign)min_len_assign }, (JsViewPropDescriptor){ .name maxLength, .type JsViewPropTypeNumber, .assign (JsViewPropAssign)max_len_assign }, (JsViewPropDescriptor){ .name defaultText, .type JsViewPropTypeString, .assign (JsViewPropAssign)default_text_assign }, (JsViewPropDescriptor){ .name defaultTextClear, .type JsViewPropTypeBool, .assign (JsViewPropAssign)default_text_clear_assign }, }};每个属性的 C 实现揭示了若干文档未言明的行为细节headerheader_assign把 JS 字符串写入上下文中的FuriString再调用底层 C 视图的text_input_set_header_text。底层函数声明位于 text_input.h即 JS 层最终复用固件内置的 GUI 模块TextInput。minLengthmin_len_assign直接将数值透传给text_input_set_minimum_length。长度约束由底层 C 视图在用户按 Save 时校验——不满足约束就不会触发结果回调这正是input事件仅在文本满足长度约束时触发的原因。maxLength与默认缓冲区源码顶部定义了#define DEFAULT_BUF_SZ 33即 32 字符文本加一个字符串结束符对应文档中默认32这一说法。max_len_assign会把缓冲区重新realloc为maxLength 1字节并设置一道保护若新maxLength小于当前defaultText长度会向 JS 抛出maxLength must be larger than defaultText length错误。因此调整maxLength时应保证不小于默认文本长度这是一个文档表格未提及、但源码明确的取值约束。defaultTextdefault_text_assign用strlcpy把默认文本复制进上下文缓冲区若缓冲区不够大则自动扩容保证缓冲区内容被完整替换而不残留旧数据。这也解释了为何gui.js示例中可以在运行中反复set(defaultText, name)来记住上一次的输入。defaultTextCleardefault_text_clear_assign仅更新上下文布尔标志并重新绑定结果回调控制底层视图在用户键入首字符时是覆盖还是追加默认文本。结果回调与跨线程交付所有属性解析器最终都会调用一次text_input_set_result_callback声明见 text_input.h 第 60 行附近把底层 C 视图的输入结果回调绑定为input_callbackstatic void input_callback(JsKbdContext* context) { furi_semaphore_release(context-input_semaphore); }从源码结构看这里的设计是一个经典的信号量 事件循环模式底层 C 视图运行在 GUI 线程用户按 Save 且长度校验通过后该线程只负责furi_semaphore_releaseJS 线程的JsKbdContext在ctx_make中注册了一个JsEventLoopContractJsEventLoopObjectTypeSemaphore当事件循环感知到信号量被释放就调用input_transformer非阻塞地获取信号量然后把context-buffer中的文本包装成 JS 字符串static mjs_val_t input_transformer(struct mjs* mjs, FuriSemaphore* semaphore, JsKbdContext* context) { furi_check(furi_semaphore_acquire(semaphore, 0) FuriStatusOk); return mjs_mk_string(mjs, context-buffer, ~0, true); }这个 Contract 对象随后被挂到视图对象的input属性上ctx_make末尾的mjs_set(mjs, view_obj, input, ...)于是 JS 代码中的views.keyboard.input才成为可订阅的事件源。换言之input事件不是轮询得到的而是由 GUI 线程释放的信号量经事件循环精确唤醒并转换而来——这也是官方文档强调必须先理解event_loop模块的根源。ctx_destroy中则对应地退订信号量并释放缓冲区、字符串与信号量资源。View eventsinput 事件官方文档列出的唯一视图事件如下ItemType说明inputstring当用户按下 Save 按钮、且文本长度满足minLength/maxLength约束时触发结合前述源码分析可以补充三点使用认知触发时机事件载荷是buffer中的完整字符串回调签名在 JS 侧表现为function (_sub, name, ...)第二个参数即字符串本体失败静默长度校验不通过时底层不回调JS 侧收不到任何事件代码中无需也不应做无效输入分支状态延续input触发后视图并未自动销毁通常做法如 gui.js 示例是切到下一个视图展示结果并把结果写回defaultText供下次使用。小结gui/text_input是 JS SDK 中最贴近表单输入需求的视图五个属性覆盖了提示、长度约束与预填文本的全部常见需求唯一的input事件在长度校验通过后携带完整字符串。它的实现位于 text_input.c属性解析器直接复用固件 GUI 模块 text_input.h 提供的TextInputC 视图并通过信号量合约把 GUI 线程的结果可靠地桥接到 JS 事件循环。官方完整可运行示例见 gui.js类型定义供 IDE 补全与类型检查见 text_input.d.ts。开发时的两个易错点保持event_loop→gui→gui/text_input的引入顺序以及保证maxLength不小于defaultText长度否则后者会抛出参数错误。【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价