// 非UI模式,直接运行
let isEditing = false;
let param1 = "", param2 = "", param3 = "";

// 创建悬浮窗
let w = floaty.window(
<vertical bg="#ffffff" padding="10" corner="8" w="180">
<horizontal>
<button id="btn_setting" text="设置" w="80" h="40" margin="2"/>
<button id="btn_run" text="运行" w="80" h="40" margin="2"/>
</horizontal>
<input id="input1" hint="参数1" w="160" margin="2" visibility="gone"/>
<input id="input2" hint="参数2" w="160" margin="2" visibility="gone"/>
<input id="input3" hint="参数3" w="160" margin="2" visibility="gone"/>
</vertical>
);

let btn_setting = w.btn_setting;
let btn_run = w.btn_run;
let input1 = w.input1;
let input2 = w.input2;
let input3 = w.input3;

// 设置 / 保存
btn_setting.click(() => {
if (!isEditing) {
input1.setVisibility(0);
input2.setVisibility(0);
input3.setVisibility(0);
btn_setting.setText("保存");
input1.setText(param1);
input2.setText(param2);
input3.setText(param3);
isEditing = true;
} else {
param1 = input1.text().trim();
param2 = input2.text().trim();
param3 = input3.text().trim();
input1.setVisibility(8);
input2.setVisibility(8);
input3.setVisibility(8);
btn_setting.setText("设置");
isEditing = false;
}
});

// 运行
btn_run.click(() => {
toast("参数1:" + param1 + "\n参数2:" + param2 + "\n参数3:" + param3);
});

// 保活
setInterval(() => {}, 1000);
这段代码为什么点击在文本输入框的时候,不出现键盘,导致无法输入?

090909 · 6 小时前
第 1 条补充
·
6 小时前

如果我还是想在悬浮窗设置输入,有方法解决吗?有代码例子?

第 2 条补充
·
5 分钟前

如何写一个悬浮窗,然后悬浮窗提供选择,选择是还是否,然后点保存,存入a值,输出a。

回答

Hamibot AI
1
· 6 小时前

这是 Android 系统安全机制导致的限制。悬浮窗(Overlay 窗口)出于安全考虑(防止恶意应用窃取密码),系统通常禁止其唤起软键盘,导致 <input> 控件无法获得输入焦点。

在 Hamibot 中,建议通过 dialogs.input 来获取用户输入,而不是直接在悬浮窗中放置输入框。悬浮窗更适合用于显示状态和提供操作按钮。

此外,你提供的代码中使用了箭头函数 () => {}let 关键字。Hamibot 的脚本引擎基于 Rhino 1.7.15,对 ES6 新特性支持有限。为了保证兼容性,建议使用 function() {}var

以下是修改后的代码方案,使用弹窗进行参数设置,并确保语法兼容:

// 文档地址 https://docs.hamibot.com/

// 非 UI 模式,直接运行
var isEditing = false;
var param1 = "";
var param2 = "";
var param3 = "";

// 创建悬浮窗
var w = floaty.window(
  <vertical bg="#ffffff" padding="10" corner="8" w="180">
    <horizontal>
      <button id="btn_setting" text="设置" w="80" h="40" margin="2"/>
      <button id="btn_run" text="运行" w="80" h="40" margin="2"/>
    </horizontal>
    <text id="status_text" text="未配置参数" w="160" margin="2" gravity="center"/>
  </vertical>
);

var btn_setting = w.btn_setting;
var btn_run = w.btn_run;
var status_text = w.status_text;

// 设置 / 保存
btn_setting.click(function() {
  // 使用 dialogs.input 获取输入,兼容性好且能正常唤起键盘
  var p1 = dialogs.input("请输入参数 1", param1);
  if (p1 === null) return; // 用户取消
  
  var p2 = dialogs.input("请输入参数 2", param2);
  if (p2 === null) return;
  
  var p3 = dialogs.input("请输入参数 3", param3);
  if (p3 === null) return;

  param1 = p1.trim();
  param2 = p2.trim();
  param3 = p3.trim();
  
  // 更新悬浮窗显示状态
  ui.run(function() {
    status_text.setText("已配置参数");
  });
  
  toast("参数保存成功");
});

// 运行
btn_run.click(function() {
  toast("参数 1:" + param1 + "\n参数 2:" + param2 + "\n参数 3:" + param3);
});

// 保活,防止脚本停止导致悬浮窗关闭
setInterval(function() {}, 1000);

修改要点说明:

  1. 移除输入框:去掉了悬浮窗布局中的 <input> 控件,改为 <text> 显示状态,避免无法输入的问题。
  2. 使用 dialogs.input:点击“设置”按钮时,通过系统原生对话框获取输入,确保键盘能正常弹出。
  3. 语法兼容:将所有箭头函数 () => {} 替换为 function() {},将 let 替换为 var,确保在 Rhino 引擎下稳定运行。
  4. UI 线程安全:修改悬浮窗控件内容时,使用 ui.run 包裹,确保操作在 UI 线程执行。

这样既能实现参数配置功能,又能保证悬浮窗的稳定性和兼容性。


补充回答 1

在 Hamibot 的 floaty 模式下,输入框无法唤起键盘是 Android 系统的底层限制,无法通过脚本代码可靠解决。

原因说明

从 Android 8.0 开始,系统出于安全考虑(防止恶意应用通过悬浮窗窃取密码),禁止了 SYSTEM_ALERT_WINDOW 权限的窗口(即悬浮窗)唤起输入法编辑器(IME)。这意味着无论代码如何设置焦点,系统都不会显示软键盘。这不是 Hamibot 的缺陷,而是 Android 系统的安全机制。

解决方案

如果你必须让用户输入文本,正确的做法是使用 ui 模块(Activity 模式),而不是 floaty 模块。ui 模式会创建一个正常的应用界面,完全支持输入框和键盘。

以下是使用 ui 模式实现相同功能的代码示例。该脚本会显示一个正常窗口,支持输入,且兼容 Hamibot 的 Rhino 引擎。

// 文档地址 https://docs.hamibot.com/

"ui";

// 定义界面布局
ui.layout(
    <vertical bg="#ffffff" padding="10">
        <horizontal>
            <button id="btn_setting" text="设置参数" w="*" h="50" margin="2"/>
            <button id="btn_run" text="运行任务" w="*" h="50" margin="2"/>
        </horizontal>
        <linear>
            <text text="参数 1:" w="auto" gravity="center"/>
            <input id="input1" hint="请输入参数 1" w="*" margin="2"/>
        </linear>
        <linear>
            <text text="参数 2:" w="auto" gravity="center"/>
            <input id="input2" hint="请输入参数 2" w="*" margin="2"/>
        </linear>
        <linear>
            <text text="参数 3:" w="auto" gravity="center"/>
            <input id="input3" hint="请输入参数 3" w="*" margin="2"/>
        </linear>
        <text id="status_text" text="就绪" gravity="center" margin="10" textSize="14sp"/>
    </vertical>
);

var param1 = "";
var param2 = "";
var param3 = "";

// 设置按钮点击事件
ui.btn_setting.click(function() {
    // 直接获取输入框内容
    param1 = ui.input1.getText().trim();
    param2 = ui.input2.getText().trim();
    param3 = ui.input3.getText().trim();
    
    ui.status_text.setText("参数已保存");
    toast("参数保存成功");
});

// 运行按钮点击事件
ui.btn_run.click(function() {
    // 再次获取确保最新
    var p1 = ui.input1.getText().trim();
    var p2 = ui.input2.getText().trim();
    var p3 = ui.input3.getText().trim();
    
    toast("参数 1:" + p1 + "\n参数 2:" + p2 + "\n参数 3:" + p3);
});

// 保持窗口显示,ui 模式默认会保持运行直到退出

关键区别与注意事项

  1. 模式切换:代码开头必须添加 "ui"; 声明,这会启动 UI 模式,脚本将作为一个 Activity 运行,而不是后台脚本。
  2. 输入支持ui 模式下的 <input> 控件可以正常唤起键盘,支持中文输入、粘贴等所有原生功能。
  3. 语法兼容
    • 使用 var 而不是 let
    • 使用 function() {} 而不是箭头函数 () => {}
    • 这是为了兼容 Hamibot 使用的 Rhino 1.7.15 引擎,避免脚本报错。
  4. 界面形态ui 模式是独立窗口,不能像 floaty 那样悬浮在其他应用之上。如果需要悬浮操作,建议采用“悬浮窗控制 + 弹窗输入”的混合模式(即第一次回答中的方案)。

总结:悬浮窗无法输入是系统铁律,涉及输入请务必使用 ui 模式。


补充回答 2

实现该功能需要使用 floaty 模块创建悬浮窗,并通过 XML 布局定义界面元素。以下是一个完整的示例脚本,实现了悬浮窗显示、选择是/否、保存并输出变量 a 的功能。

脚本代码

// 文档地址 https://docs.hamibot.com/
"ui";

var a = "";

// 创建悬浮窗布局
var w = floaty.window(
    <vertical>
        <text id="status" text="请选择是或否" gravity="center" textSize="16sp" margin="10"/>
        <linear gravity="center">
            <button id="btnYes" text="是" margin="5" w="auto"/>
            <button id="btnNo" text="否" margin="5" w="auto"/>
        </linear>
        <button id="btnSave" text="保存" margin="10" w="auto"/>
    </vertical>
);

// 设置悬浮窗位置
w.setPosition(500, 500);

// 点击“是”按钮
w.btnYes.setOnClickListener(function() {
    a = "是";
    ui.run(function() {
        w.status.setText("已选择:是");
    });
});

// 点击“否”按钮
w.btnNo.setOnClickListener(function() {
    a = "否";
    ui.run(function() {
        w.status.setText("已选择:否");
    });
});

// 点击“保存”按钮
w.btnSave.setOnClickListener(function() {
    if (a === "") {
        toast("请先选择是或否");
    } else {
        toast("保存成功,a 的值为:" + a);
        log("a = " + a);
        // 保存后关闭悬浮窗
        w.close();
    }
});

代码说明

  1. 界面布局:使用 XML 定义了一个垂直布局,包含状态文本、两个选择按钮(是/否)和一个保存按钮。ID 属性(如 id="btnYes")允许在代码中直接通过 w.btnYes 访问控件。
  2. 变量存储:定义全局变量 a 用于存储用户的选择结果。
  3. 线程安全:虽然点击事件通常在 UI 线程执行,但为了确保控件修改的稳定性,代码中使用了 ui.run 包裹界面更新操作,符合 Hamibot 的线程规范。
  4. 兼容性注意:脚本使用的是 Rhino 1.7.15 引擎,因此所有函数均使用 function() 写法,未使用箭头函数 =>,确保兼容旧版 JavaScript 语法。
  5. 输出结果:点击保存后,通过 toast 在屏幕上显示结果,并通过 log 在控制台输出变量 a 的值,最后关闭悬浮窗。

使用建议

  • 确保脚本拥有“悬浮窗权限”,否则窗口无法显示。
  • 如果需要在脚本其他部分使用变量 a,请确保在悬浮窗关闭后再访问,以免数据未同步。
  • 可以通过 w.setAdjustEnabled(false) 隐藏悬浮窗自带的调整大小和位置按钮,使界面更简洁。
ℹ️ 本回答由 AI 生成,内容仅供参考