小丑鼠

JokyMouse 开发者文档

小丑鼠 Latest

脚本设置

settings 是一个节点树数组。你在脚本元信息里声明它,运行时再通过 jm.settings() 读取结果。

local jm = require("jokymouse")
local settings = jm.settings()

一句话原则

  • 没有动态数组时,优先让结果保持平铺或浅层对象。
  • 有动态数组的节点,运行时会直接得到数组,不需要再读 .children

settings JSON Schema

type ScriptSetting = {
  type: ScriptSettingType;
  key?: string;
  label?: string;
  label_tooltip?: string;
  default?: any;
  options?: { value: any; label: string }[];
  number?: {
    default?: any;
    min?: number;
    max?: number;
    step?: number;
  };
  range?: {
    default?: any;
    min?: number;
    max?: number;
    step?: number;
    suffix?: string;
  };
  foldable?: boolean;
  children?: ScriptSetting[];
};

通用字段

字段说明
type节点类型
key当前节点在结果对象里的字段名
label标签文本
label_tooltip标签右侧提示
default默认值
optionsselect / input-datalist 选项
numberinput-number 配置
rangeslider / range-slider 配置
foldable分组节点是否可折叠
children子节点

运行时结果规则

  • key 的普通控件,运行时直接得到基础值。
  • key 的结构节点,运行时得到一个对象,里面是它的子字段。
  • 没有 key 的结构节点,只负责布局,子字段会继续并入上一层。
  • type: "list" 的节点,运行时直接得到数组,不需要自己再取 children

平铺型

[
  {
    "key": "account",
    "type": "label#input",
    "label": "账号"
  },
  {
    "key": "password",
    "type": "label#input",
    "label": "密码"
  }
]

运行时:

local settings = jm.settings()
settings.account
settings.password

动态数组型

[
  {
    "type": "list",
    "key": "accounts",
    "label": "账号列表",
    "children": [
      {
        "type": "row",
        "children": [
          {
            "key": "username",
            "type": "label#input",
            "label": "账号"
          },
          {
            "key": "password",
            "type": "label#input",
            "label": "密码"
          }
        ]
      }
    ]
  }
]

运行时:

local settings = jm.settings()

for _, item in ipairs(settings.accounts) do
  print(item.username, item.password)
end

分组对象型

[
  {
    "type": "label",
    "key": "advanced",
    "label": "高级设置",
    "children": [
      {
        "key": "enabled",
        "type": "label#checkbox",
        "label": "启用",
        "default": true
      },
      {
        "key": "retry_count",
        "type": "label#input-number",
        "label": "重试次数",
        "number": {
          "default": 3,
          "min": 0
        }
      }
    ]
  }
]

运行时:

local settings = jm.settings()

if settings.advanced.enabled then
  print(settings.advanced.retry_count)
end

组件怎么写

label

分组节点,也可以带 children。如果自己有 key,运行时会得到一个对象。

{
  "type": "label",
  "key": "advanced",
  "label": "高级设置",
  "foldable": true,
  "children": []
}

divider

纯展示分隔线,不参与值存储。

{
  "type": "divider",
  "label": "高级设置",
  "label_tooltip": "以下选项建议熟悉脚本后再修改"
}

row

横向布局容器。通常不需要自己提供 key

{
  "type": "row",
  "children": [
    {
      "key": "keys",
      "type": "label#key-recorder",
      "label": "按键"
    },
    {
      "key": "interval",
      "type": "label#input-number",
      "label": "间隔",
      "number": {
        "default": 1000,
        "min": 1,
        "step": 1
      }
    }
  ]
}

list

数组容器。必须提供 key,并且 children 必须且只能放 1 个模板节点。

{
  "type": "list",
  "key": "accounts",
  "label": "账号列表",
  "children": [
    {
      "type": "row",
      "children": [
        {
          "key": "username",
          "type": "label#input",
          "label": "账号"
        },
        {
          "key": "password",
          "type": "label#input",
          "label": "密码"
        }
      ]
    }
  ]
}

select / label#select

{
  "key": "click_type",
  "type": "label#select",
  "label": "点击类型",
  "default": "single",
  "options": [
    { "value": "single", "label": "单击" },
    { "value": "double", "label": "双击" }
  ]
}

input / label#input

普通文本输入框。

{
  "key": "window_name",
  "type": "label#input",
  "label": "窗口名称",
  "default": ""
}

input-datalist / label#input-datalist

可输入,也可从候选项中选择。

{
  "key": "repeat_times",
  "type": "label#input-datalist",
  "label": "重复次数",
  "default": 10,
  "options": [
    { "value": 10, "label": "10" },
    { "value": 100, "label": "100" },
    { "value": -1, "label": "无限" }
  ]
}

input-number / label#input-number

必须提供 number

{
  "key": "click_interval",
  "type": "label#input-number",
  "label": "点击间隔(毫秒)",
  "number": {
    "default": 1000,
    "min": 1,
    "max": 100000,
    "step": 1
  }
}

checkbox / label#checkbox

{
  "key": "loop_forever",
  "type": "label#checkbox",
  "label": "循环执行",
  "default": false
}

key-recorder / label#key-recorder

值类型是 string[]

{
  "key": "hotkey",
  "type": "label#key-recorder",
  "label": "启动热键",
  "default": ["ctrl", "shift", "k"]
}

slider / label#slider

必须提供 range

{
  "key": "speed",
  "type": "label#slider",
  "label": "速度",
  "range": {
    "min": 1,
    "max": 10,
    "step": 1,
    "default": 5,
    "suffix": "x"
  }
}

range-slider / label#range-slider

双滑块,必须提供 range

{
  "key": "random_interval",
  "type": "label#range-slider",
  "label": "额外随机间隔",
  "range": {
    "min": 0,
    "max": 1000,
    "step": 10,
    "default": {
      "min": 0,
      "max": 0
    },
    "suffix": "ms"
  }
}

校验规则

  • settings 必须是数组
  • type 必须是支持的节点类型
  • labellabel#xxx 必须提供 label
  • 顶层参与值存储的节点必须提供 key
  • list 节点必须提供 key
  • list 节点的 children 必须且只能提供 1 个模板节点
  • divider 不能有 children
  • input-number 必须提供 number
  • slider / range-slider 必须提供 range
  • key 不能使用保留字 valuechildren
  • 同级 key 不能重复
  • 控件节点不能同时作为 list 容器

推荐写法

  • 大多数控件优先用 label#xxx
  • 没有动态数组时,全部平铺即可
  • 有动态数组的节点,直接用 list
  • list 只负责数组结构,不要再给它叠加控件值
  • 不要为了“看起来统一”把简单配置也包成很多层