# 插件API手册
# onPluginReady
- 参数
- callback: 初始化完成回调函数,签名:- (data) => void- data.actionName: 动作名称
- data.actionMatch: 匹配到的动作(- ActionMatch | null)
- data.actionMatchFiles: 匹配到的文件列表(- FileItem[])
- data.requestId: 请求ID
- data.reenter: 是否重新进入,对于 singleton 的插件,当再次调用时为 true
- data.isView: 是否是快捷面板
- data.type: 类型,可选值:- "action"|- "callPage"
 
 
- 返回
- void: 无返回值
 
插件应用初始化完成时触发
focusany.onPluginReady((data) => {
    // data.actionName 动作名称
    // data.actionMatch 动作
    // data.actionMatchFiles 匹配到的文件
    // data.requestId 请求ID
    // data.reenter 是否重新进入,对于 singleton 的插件,当再次调用时为 true
    // data.isView 是否是快捷面板
    // data.type 类型
});
2
3
4
5
6
7
8
9
# onPluginExit
- 参数
- callback: 退出时的回调函数,签名:- () => void
 
- 返回
- void: 无返回值
 
插件应用退出时触发
focusany.onPluginExit(() => {
    // 插件即将退出
});
2
3
# onPluginEvent
- 参数
- event: 事件类型,可选值:- "ClipboardChange"|- "UserChange"
- callback: 事件回调函数- data: 事件数据
 
 
- 返回
- void: 无返回值
 
插件事件监听
// 剪切板变化
focusany.onPluginEvent('ClipboardChange', (data) => {
    console.log('剪切板变化', data);
})
// 用户变化
focusany.onPluginEvent('UserChange', (data) => {
    console.log('用户变化', data);
})
2
3
4
5
6
7
8
# offPluginEvent
- 参数
- event: 事件类型,可选值:- "ClipboardChange"|- "UserChange"
- callback: 要移除的事件回调函数
 
- 返回
- void: 无返回值
 
移除插件事件
focusany.offPluginEvent('ClipboardChange',cb);
focusany.offPluginEvent('UserChange',cb);
2
# offPluginEventAll
- 参数
- event: 事件类型,可选值:- "ClipboardChange"|- "UserChange"
 
- 返回
- void: 无返回值
 
移除所有插件事件
focusany.offPluginEventAll('ClipboardChange');
focusany.offPluginEventAll('UserChange');
2
# onMoreMenuClick
- 参数
- callback: 菜单点击回调函数- data: 点击数据- name: 菜单项名称
 
 
 
- 返回
- void: 无返回值
 
插件更多菜单点击事件
focusany.onMoreMenuClick((data) => {
    console.log('更多菜单点击', data.name);
});
2
3
# registerHotkey
- 参数
- key: 热键定义,支持多种格式:- string: 简单热键字符串(如- "ctrl+shift+a")
- string[]: 多个热键字符串数组
- HotkeyQuickType: 快捷热键类型(如- "save")
- HotkeyType: 热键对象- key: 按键
- modifiers: 修饰键数组,可选值:- "Control"|- "Option"|- "Command"|- "Ctrl"|- "Alt"|- "Win"|- "Meta"|- "Shift"
 
- HotkeyType[]: 多个热键对象数组
 
- callback: 热键触发回调函数
 
- 返回
- void: 无返回值
 
注册热键
// 注册单个热键
focusany.registerHotkey('ctrl+shift+a', () => {
    console.log('热键触发');
});
// 注册多个热键
focusany.registerHotkey(['ctrl+shift+a', 'cmd+shift+a'], () => {
    console.log('热键触发');
});
// 注册快捷热键
focusany.registerHotkey('save', () => {
    console.log('保存热键触发');
});
// 注册复杂热键
focusany.registerHotkey({
    key: 'a',
    modifiers: ['Control', 'Shift']
}, () => {
    console.log('热键触发');
});
// 注册多个复杂热键
focusany.registerHotkey([
    { key: 'a', modifiers: ['Control', 'Shift'] },
    { key: 'a', modifiers: ['Command', 'Shift'] }
], () => {
    console.log('热键触发');
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# unregisterHotkeyAll
- 参数
- 无
 
- 返回
- void: 无返回值
 
取消注册所有热键
focusany.unregisterHotkeyAll();
# isMainWindowShown
- 参数
- 无
 
- 返回
- boolean: 是否显示主窗口
 
插件主窗口是否显示
focusany.isMainWindowShown();
# hideMainWindow
- 参数
- 无
 
- 返回
- boolean: 操作是否成功
 
隐藏插件主窗口
focusany.hideMainWindow();
# showMainWindow
- 参数
- 无
 
- 返回
- boolean: 操作是否成功
 
显示插件主窗口
focusany.showMainWindow();
# isFastPanelWindowShown
- 参数
- 无
 
- 返回
- boolean: 快捷面板窗口是否显示
 
快捷面板窗口是否显示
focusany.isFastPanelWindowShown();
# showFastPanelWindow
- 参数
- 无
 
- 返回
- boolean: 操作是否成功
 
显示快捷面板窗口
focusany.showFastPanelWindow();
# hideFastPanelWindow
- 参数
- 无
 
- 返回
- boolean: 操作是否成功
 
隐藏快捷面板窗口
focusany.hideFastPanelWindow();
# setExpendHeight
- 参数
- height: 插件高度(像素)
 
- 返回
- void: 无返回值
 
设置插件的高度
focusany.setExpendHeight(300);
# setSubInput
- 参数
- onChange: 输入变化回调函数- keywords: 输入的关键字
 
- placeholder: 输入框占位符文本(可选)
- isFocus: 是否自动聚焦(可选)
- isVisible: 是否显示(可选)
 
- 返回
- boolean: 设置是否成功
 
设置输入框监听
focusany.setSubInput((keywords) => {
    console.log('输入变化', keywords);
}, '请输入关键字', true, true);
2
3
# removeSubInput
- 参数
- 无
 
- 返回
- boolean: 移除是否成功
 
移除输入框监听
focusany.removeSubInput();
# setSubInputValue
- 参数
- value: 要设置的输入框值
 
- 返回
- boolean: 设置是否成功
 
设置子输入框的值
focusany.setSubInputValue('测试');
# subInputBlur
- 参数
- 无
 
- 返回
- boolean: 操作是否成功
 
子输入框失去焦点
focusany.subInputBlur();
# getPluginRoot
- 参数
- 无
 
- 返回
- string: 插件根目录路径
 
获取插件根目录
focusany.getPluginRoot();
# getPluginConfig
- 参数
- 无
 
- 返回
- object | null: 插件配置对象- name: 插件名称
- title: 插件标题
- version: 插件版本
- logo: 插件图标
 
 
获取插件配置文件 config.json
const config = focusany.getPluginConfig();
// config.name 插件名称
// config.title 插件标题
// config.version 插件版本
// config.logo 插件图标
2
3
4
5
# getPluginInfo
- 参数
- 无
 
- 返回
- object: 插件信息对象- nodeIntegration: 是否启用Node集成
- preloadBase: 预加载基础路径
- preload: 预加载文件路径
- main: 主文件路径
- mainView: 主视图文件路径
- width: 窗口宽度
- height: 窗口高度
- autoDetach: 是否自动分离
- singleton: 是否单例模式
- zoom: 缩放比例
 
 
获取插件信息
focusany.getPluginInfo();
# getPluginEnv
- 参数
- 无
 
- 返回
- "dev" | "prod": 插件运行环境
 
获取插件环境
// dev 或 prod
focusany.getPluginEnv();
2
# getQuery
- 参数
- requestId: 请求ID
 
- 返回
- SearchQuery: 查询信息对象- keywords: 搜索关键字
- currentFiles: 当前文件列表(可选)
- currentImage: 当前图片(可选)
- currentText: 当前文本(可选)
 
 
获取插件查询信息
focusany.onPluginReady((data) => {
    const query = focusany.getQuery(data.requestId);
    // query.keywords 关键字
    // query.currentFiles 当前文件列表
    // query.currentImage 当前图片
    // query.currentText 当前文本
});
2
3
4
5
6
7
# createBrowserWindow
- 参数
- url: 窗口加载的URL路径
- options: 窗口初始化选项(BrowserWindow.InitOptions)
- callback: 窗口创建完成回调函数(可选)
 
- 返回
- BrowserWindow.WindowInstance: 窗口实例
 
创建窗口
const browserWindow = focusany.createBrowserWindow('path/to/page.html', {
    width: 800,
    height: 600,
}, () => {
    console.log('窗口创建完成');
});
2
3
4
5
6
# outPlugin
- 参数
- 无
 
- 返回
- boolean: 操作是否成功
 
关闭插件
focusany.outPlugin();
# isDarkColors
- 参数
- 无
 
- 返回
- boolean: 是否为暗色主题
 
是否是暗色主题
focusany.isDarkColors();
# showUserLogin
- 参数
- 无
 
- 返回
- void: 无返回值
 
显示用户登录窗口
focusany.showUserLogin();
# getUser
- 参数
- 无
 
- 返回
- object: 用户信息对象- isLogin: 是否已登录
- avatar: 用户头像
- nickname: 用户昵称
- vipFlag: 会员标识
- deviceCode: 设备代码
- openId: 用户OpenId
 
 
获取用户
const user = focusany.getUser();
// user.isLogin 是否登录
// user.avatar 头像
// user.nickname 昵称
// user.vipFlag 会员标识
// user.deviceCode 设备ID
// user.openId 用户OpenId,每个用户对每个插件的标识唯一
2
3
4
5
6
7
# getUserAccessToken
- 参数
- 无
 
- 返回
- Promise<object>: 访问令牌信息- token: 访问令牌
- expireAt: 过期时间戳
 
 
获取用户访问令牌
const accessToken = await focusany.getUserAccessToken();
// accessToken.token 访问令牌
// accessToken.expireAt 过期时间
2
3
# listGoods
- 参数
- query: 查询参数(可选)- ids: 商品ID数组(可选)
 
 
- 返回
- Promise<array>: 商品列表- id: 商品ID
- title: 商品标题
- cover: 商品封面
- priceType: 价格类型(- "fixed"|- "dynamic")
- fixedPrice: 固定价格
- description: 商品描述
 
 
获取商品列表
const goods = await focusany.listGoods();
结果示例
[
    {
        "id": "goodsId",
        "title": "商品名称",
        "cover": "商品封面",
        // 商品价格类型 fixed: 固定价格,dynamic: 动态价格
        "priceType": "fixed",
        // 固定价格
        "fixedPrice": "0.01",
        "description": "商品描述"
    }
]
2
3
4
5
6
7
8
9
10
11
12
# openGoodsPayment
- 参数
- options: 订单参数- goodsId: 插件商品ID
- price: 插件商品价格(可选,动态价格商品需传入)
- outOrderId: 第三方订单号(可选,最大长度64字符)
- outParam: 参数数据(可选,长度不超过200字符)
 
 
- 返回
- Promise<object>: 支付结果- paySuccess: 是否支付成功
 
 
创建订单并显示
const result = await focusany.openGoodsPayment({
    // 插件商品ID
    goodsId: 'xxx',
    // 插件商品价格,固定价格商品无需传入,动态价格商品需传入价格,如 0.01
    price: '0.01',
    // 第三方订单号,字符串,最大长度 64 字符
    outOrderId: 'xxxx',
    // 参数数据,长度不超过 200 字符
    outParam: 'xxxx',
});
// result.paySuccess 是否支付成功,注意,支付是否成功需要依赖服务端的回调,此处仅作参考
2
3
4
5
6
7
8
9
10
11
# queryGoodsOrders
- 参数
- options: 查询参数- goodsId: 插件商品ID(可选)
- page: 分页页码,从1开始(可选)
- pageSize: 分页大小,默认10(可选)
 
 
- 返回
- Promise<object>: 订单查询结果- page: 当前页数
- total: 总订单数
- records: 订单列表- id: 订单号
- goodsId: 商品ID
- status: 订单状态(- "Paid"|- "Unpaid")
 
 
 
查询插件商品订单
const result = await focusany.queryGoodsOrders({
    // 插件商品ID,可选
    goodsId: 'xxx',
    // 分页页码,从 1 开始,可选
    page: 1,
    // 分页大小,可选,默认是 10
    pageSize: 10,
})
2
3
4
5
6
7
8
结果示例
{
    "total": 1,
    "page": 1,
    "records": [
        {
            // 订单号
            "id": "xxxx",
            // 插件商品ID
            "goodsId": "xxx",
            // 状态 Paid: 已支付, Unpaid: 未支付
            "status": "Paid"
        }
    ]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# apiPost
- 参数
- url: 请求URL
- body: 请求体数据
- option: 请求选项
 
- 返回
- Promise<object>: 响应结果- code: 状态码
- msg: 消息
- data: 响应数据
 
 
请求官方接口
const result = await focusany.apiPost('/api/test', { data: 'test' }, {});
// result.code 状态码
// result.msg 消息
// result.data 数据
2
3
4
# setAction
- 参数
- action: 插件动作配置,支持单个或数组- fullName: 完整名称(可选)
- name: 动作名称
- title: 动作标题
- matches: 匹配规则数组
- platform: 支持的平台数组(可选,- "win"|- "osx"|- "linux")
- icon: 图标(可选)
- type: 动作类型(可选,- "command"|- "web"|- "code"|- "backend")
 
 
- 返回
- boolean: 设置是否成功
 
动态设置插件动作
设置一个动作
focusany.setAction({
    name: 'actionName',
    title: '动作名称',
    icon: 'icon',
    type: 'web', // command | web | code | backend
    platform: ['win', 'osx', 'linux'], // 支持的平台
    matches: [
        {
            type: 'text',
            text: '匹配文本',
            minLength: 1,
            maxLength: 100
        }
    ]
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
设置多个动作
focusany.setAction([
    {
        name: 'actionName1',
        title: '动作名称1',
        icon: 'icon1',
        type: 'web',
        matches: []
    },
    {
        name: 'actionName2',
        title: '动作名称2',
        icon: 'icon2',
        type: 'command',
        matches: []
    },
]);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# removeAction
- 参数
- name: 要移除的动作名称
 
- 返回
- boolean: 移除是否成功
 
移除插件动作
focusany.removeAction('actionName');
# getActions
- 参数
- names: 动作名称数组(可选)
 
- 返回
- PluginAction[]: 插件动作数组
 
获取插件动作
focusany.getActions();
示例结果
[
    {
        "fullName": "完整名称",
        "name": "actionName",
        "title": "动作名称",
        "icon": "icon",
        "type": "web",
    }
]
2
3
4
5
6
7
8
9
# redirect
- 参数
- keywordsOrAction: 关键字或动作名称,支持字符串或字符串数组
- query: 查询参数(可选)- keywords: 搜索关键字
- currentFiles: 当前文件列表(可选)
- currentImage: 当前图片(可选)
- currentText: 当前文本(可选)
 
 
- 返回
- void: 无返回值
 
打开插件动作
// 通过动作名称打开
focusany.redirect('actionName');
// 通过关键字打开
focusany.redirect('关键字');
// 通过多个关键字打开
focusany.redirect(['关键字1', '关键字2']);
// 带查询参数打开
focusany.redirect('actionName', {
    keywords: '搜索关键字',
    currentFiles: [], // 当前文件列表
    currentImage: '', // 当前图片
    currentText: ''   // 当前文本
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# showToast
- 参数
- body: 提示内容
- options: 提示选项(可选)- duration: 显示持续时间(毫秒,可选)
- status: 提示状态(可选,- "info"|- "success"|- "error")
 
 
- 返回
- void: 无返回值
 
显示提示
focusany.showToast('提示内容', { duration: 3000, status: 'info' });
# showNotification
- 参数
- body: 通知内容
- clickActionName: 点击通知时执行的动作名称(可选)
 
- 返回
- void: 无返回值
 
显示通知
// 显示通知
focusany.showNotification('通知内容');
// 显示通知,点击执行动作
focusany.showNotification('通知内容','clickActionName');
2
3
4
# showMessageBox
- 参数
- message: 消息内容
- options: 消息框选项- title: 消息框标题(可选)
- yes: 确定按钮文本(可选)
- no: 取消按钮文本(可选)
 
 
- 返回
- boolean: 如果点击"是"返回 true,如果点击"否"返回 false
 
显示消息框
const result = focusany.showMessageBox('消息内容', { title: '消息标题', yes: '确定', no: '取消' });
// result 为 true 或 false
2
# showOpenDialog
- 参数
- options: 文件选择框选项- title: 对话框标题(可选)
- defaultPath: 默认路径(可选)
- buttonLabel: 按钮标签(可选)
- filters: 文件过滤器数组(可选)- name: 过滤器名称
- extensions: 文件扩展名数组
 
- properties: 属性数组(可选)
- message: 消息(可选)
- securityScopedBookmarks: 安全范围书签(可选)
 
 
- 返回
- string[] | undefined: 选择的文件路径数组
 
打开文件选择框
const result = focusany.showOpenDialog({
    title: '选择文件',
    defaultPath: '/home/user',
    buttonLabel: '选择',
    filters: [
        { name: '图片', extensions: ['jpg', 'png', 'gif'] },
        { name: '文档', extensions: ['pdf', 'doc', 'docx'] }
    ],
    properties: ['openFile', 'multiSelections'],
    message: '请选择文件',
    securityScopedBookmarks: false
});
// result 为文件路径数组
2
3
4
5
6
7
8
9
10
11
12
13
# showSaveDialog
- 参数
- options: 文件保存框选项- title: 对话框标题(可选)
- defaultPath: 默认路径(可选)
- buttonLabel: 按钮标签(可选)
- filters: 文件过滤器数组(可选)- name: 过滤器名称
- extensions: 文件扩展名数组
 
- message: 消息(可选)
- nameFieldLabel: 名称字段标签(可选)
- showsTagField: 标签字段(可选)
- properties: 属性数组(可选)
- securityScopedBookmarks: 安全范围书签(可选)
 
 
- 返回
- string | undefined: 保存的文件路径
 
打开文件保存框
const result = focusany.showSaveDialog({
    title: '保存文件',
    defaultPath: '/home/user/document.pdf',
    buttonLabel: '保存',
    filters: [
        { name: '图片', extensions: ['jpg', 'png', 'gif'] },
        { name: '文档', extensions: ['pdf', 'doc', 'docx'] }
    ],
    message: '选择保存位置',
    nameFieldLabel: '文件名',
    showsTagField: '标签',
    properties: ['showHiddenFiles', 'createDirectory'],
    securityScopedBookmarks: false
});
// result 为保存的文件路径
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# screenCapture
- 参数
- callback: 截图完成回调函数- imgBase64: 截图的Base64编码字符串
 
 
- 返回
- void: 无返回值
 
截图
focusany.screenCapture((imgBase64) => {
    console.log('截图文件',imgBase64);
});
2
3
# getNativeId
- 参数
- 无
 
- 返回
- string: 设备ID
 
获取设备ID
focusany.getNativeId();
# getAppVersion
- 参数
- 无
 
- 返回
- string: 软件版本号
 
获取软件版本
focusany.getAppVersion();
# getPath
- 参数
- name: 路径名称,可选值:- "home"|- "appData"|- "userData"|- "temp"|- "exe"|- "desktop"|- "documents"|- "downloads"|- "music"|- "pictures"|- "videos"|- "logs"
 
- 返回
- string: 对应的系统路径
 
获取路径
// 获取用户目录
focusany.getPath('home');
// 获取应用数据目录
focusany.getPath('appData');
// 获取用户数据目录
focusany.getPath('userData');
// 获取临时目录
focusany.getPath('temp');
// 获取应用目录
focusany.getPath('exe');
// 获取桌面目录
focusany.getPath('desktop');
// 获取文档目录
focusany.getPath('documents');
// 获取下载目录
focusany.getPath('downloads');
// 获取音乐目录
focusany.getPath('music');
// 获取图片目录
focusany.getPath('pictures');
// 获取视频目录
focusany.getPath('videos');
// 获取日志目录
focusany.getPath('logs');
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# getFileIcon
- 参数
- path: 文件路径
 
- 返回
- string: 文件图标的Base64编码
 
获取文件图标
focusany.getFileIcon('path.txt');
# copyFile
- 参数
- file: 文件路径,支持字符串或字符串数组
 
- 返回
- boolean: 复制是否成功
 
复制文件到剪贴板
// 复制单个文件
focusany.copyFile('/path/to/file.txt');
// 复制多个文件
focusany.copyFile(['/path/to/file1.txt', '/path/to/file2.txt']);
2
3
4
5
# copyImage
- 参数
- image: 图片路径或Base64编码
 
- 返回
- boolean: 复制是否成功
 
复制图片到剪贴板
focusany.copyImage('/path/to/image.png');
# copyText
- 参数
- text: 要复制的文本
 
- 返回
- boolean: 复制是否成功
 
复制文本到剪贴板
focusany.copyText('text');
# getClipboardText
- 参数
- 无
 
- 返回
- string: 剪贴板中的文本内容
 
获取剪贴板文本
// 输出剪贴板文本
const result = focusany.getClipboardText();
2
# getClipboardImage
- 参数
- 无
 
- 返回
- string: 剪贴板中图片的Base64编码
 
获取剪贴板图片
// 输出图片的 base64 编码
const result = focusany.getClipboardImage();
2
# getClipboardFiles
- 参数
- 无
 
- 返回
- FileItem[]: 剪贴板中的文件列表- name: 文件名
- isDirectory: 是否为目录
- isFile: 是否为文件
- path: 文件路径
- fileExt: 文件扩展名
 
 
获取剪贴板文件
// 输出剪贴板文件
const result = focusany.getClipboardFiles();
2
结果示例
[
    {
        "name": "文件名",
        "isDirectory": false,
        "isFile": true,
        "path": "文件路径",
        "fileExt": "文件扩展名",
    }
]
2
3
4
5
6
7
8
9
# listClipboardItems 剪贴板历史
- 参数
- option: 选项(可选)- limit: 限制返回数量(可选)
 
 
- 返回
- Promise<array>: 剪贴板历史列表- type: 类型(- "file"|- "image"|- "text")
- timestamp: 时间戳
- files: 文件列表(可选)
- image: 图片(可选)
- text: 文本(可选)
 
 
获取剪贴板历史
const items = await focusany.listClipboardItems({ limit: 10 });
# deleteClipboardItem 删除剪贴板项
- 参数
- timestamp: 要删除的时间戳
 
- 返回
- Promise<void>: 无返回值
 
根据时间戳删除剪贴板项
await focusany.deleteClipboardItem(1628760000000);
# clearClipboardItems 清空剪贴板
- 参数
- 无
 
- 返回
- Promise<void>: 无返回值
 
清空剪贴板历史
await focusany.clearClipboardItems();
# shellOpenPath
- 参数
- fullPath: 文件完整路径
 
- 返回
- void: 无返回值
 
使用默认的应用打开文件
focusany.shellOpenPath('/path/to/file.doc');
# shellShowItemInFolder
- 参数
- fullPath: 文件完整路径
 
- 返回
- void: 无返回值
 
在文件管理器中显示文件
focusany.shellShowItemInFolder('/path/to/file.txt');
# shellOpenExternal
- 参数
- url: 要打开的链接URL
 
- 返回
- void: 无返回值
 
打开链接
focusany.shellOpenExternal('https://focusany.com');
# shellBeep
- 参数
- 无
 
- 返回
- void: 无返回值
 
播放提示音
focusany.shellBeep();
# simulate 模拟操作
# simulate.keyboardTap 模拟按键
- 参数
- key: 按键
- modifiers: 修饰键数组,可选值:- "ctrl"|- "shift"|- "command"|- "option"|- "alt"
 
- 返回
- Promise<void>: 无返回值
 
模拟键盘按键
// 模拟按键组合
await focusany.simulate.keyboardTap('a', ['ctrl', 'shift']);
// 支持的修饰键: 'ctrl', 'shift', 'command', 'option', 'alt'
await focusany.simulate.keyboardTap('c', ['ctrl']);
await focusany.simulate.keyboardTap('v', ['command']);
2
3
4
5
6
# simulate.typeString 模拟输入
- 参数
- text: 要输入的文本
 
- 返回
- Promise<void>: 无返回值
 
模拟输入字符串
await focusany.simulate.typeString('Hello World');
# simulate.mouseToggle 鼠标按下
- 参数
- type: 动作类型(- "down"|- "up")
- button: 鼠标按钮(- "left"|- "right"|- "middle")
 
- 返回
- Promise<void>: 无返回值
 
模拟鼠标按下或松开
await focusany.simulate.mouseToggle('down', 'left');
await focusany.simulate.mouseToggle('up', 'left');
2
# simulate.mouseMove 鼠标移动
- 参数
- x: X坐标
- y: Y坐标
 
- 返回
- Promise<void>: 无返回值
 
模拟鼠标移动
await focusany.simulate.mouseMove(100, 200);
# simulate.mouseClick 鼠标点击
- 参数
- button: 鼠标按钮(- "left"|- "right"|- "middle")
- double: 是否双击(可选)
 
- 返回
- Promise<void>: 无返回值
 
模拟鼠标点击
await focusany.simulate.mouseClick('left');
await focusany.simulate.mouseClick('left', true); // 双击
2
# getCursorScreenPoint
- 参数
- 无
 
- 返回
- object: 鼠标位置坐标- x: X坐标
- y: Y坐标
 
 
获取鼠标位置
// 输出 {x: 100, y: 200}
const result = focusany.getCursorScreenPoint();
2
# getDisplayNearestPoint
- 参数
- point: 坐标点- x: X坐标
- y: Y坐标
 
 
- 返回
- any: 显示器信息对象
 
获取指定位置最近的显示器信息
const result = focusany.getDisplayNearestPoint({ x: 100, y: 200 });
输出示例
{
    "id": "显示器ID",
    "bounds": {
        "x": 0,
        "y": 0,
        "width": 1920,
        "height": 1080
    },
    "workArea": {
        "x": 0,
        "y": 0,
        "width": 1920,
        "height": 1080
    },
    "scaleFactor": 1.0
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# isMacOs
- 参数
- 无
 
- 返回
- boolean: 是否为MacOS系统
 
是否是MacOS
focusany.isMacOs();
# isWindows
- 参数
- 无
 
- 返回
- boolean: 是否为Windows系统
 
是否是Windows
focusany.isWindows();
# isLinux
- 参数
- 无
 
- 返回
- boolean: 是否为Linux系统
 
是否是Linux
focusany.isLinux();
# getPlatformArch
- 参数
- 无
 
- 返回
- "x86" | "arm64" | null: 平台架构
 
获取平台架构
// 返回值: 'x86' | 'arm64' | null
const arch = focusany.getPlatformArch();
2
# sendBackendEvent
- 参数
- event: 事件名称
- data: 事件数据(可选)
- option: 选项(可选)- timeout: 超时时间(毫秒)
 
 
- 返回
- Promise<any>: 事件响应数据
 
发送后端事件
// 发送事件
focusany.sendBackendEvent('event', { data }, { timeout: 3000 });
// 发送事件并等待响应
const result = await focusany.sendBackendEvent('event', { data }, { timeout: 3000 });
2
3
4
5
# registerCallPage
- 参数
- type: 类型
- callback: 回调函数- resolve: 解决函数- data: 输出数据
 
- reject: 拒绝函数- error: 错误信息
 
- data: 输入数据
 
- option: 选项(可选)- timeout: 超时时间(毫秒)
 
 
- 返回
- void: 无返回值
 
在 web 中注册后端调用器
focusany.registerCallPage('type', (resolve, reject, data) => {
    // 处理数据
    resolve({ result: 'success' });
}, { timeout: 5000 });
2
3
4
# callPage
- 参数
- type: 类型
- data: 数据(可选)
- option: 选项(可选)- waitReadyTimeout: 等待就绪超时时间(毫秒,默认 10000)
- timeout: 超时时间(毫秒,默认 60000)
- showWindow: 是否显示窗口(默认 true)
- autoClose: 是否自动关闭(默认 true)
 
 
- 返回
- Promise<any>: 响应数据
 
从后端脚本调用后端
const result = await focusany.callPage('type', { input: 'data' }, {
    waitReadyTimeout: 10000,
    timeout: 60000,
    showWindow: true,
    autoClose: true
});
2
3
4
5
6
# llmListModels
- 参数
- 无
 
- 返回
- Promise<array>: 大语言模型列表- providerId: 提供商ID
- providerLogo: 提供商图标
- providerTitle: 提供商名称
- modelId: 模型ID
- modelName: 模型名称
 
 
获取大语言模型列表
const models = await focusany.llmListModels();
// models 为模型列表
2
结果示例
[
    {
        "providerId": "openai",
        "providerLogo": "https://example.com/logo.png",
        "providerTitle": "OpenAI",
        "modelId": "gpt-3.5-turbo",
        "modelName": "GPT-3.5 Turbo"
    }
]
2
3
4
5
6
7
8
9
# llmChat
- 参数
- callInfo: 调用信息- providerId: 提供商ID
- modelId: 模型ID
- message: 消息内容
 
 
- 返回
- Promise<object>: 对话响应结果- code: 状态码
- msg: 消息
- data: 响应数据(可选)- message: 回复消息
 
 
 
调用大语言模型对话
const result = await focusany.llmChat({
    providerId: 'openai',
    modelId: 'gpt-3.5-turbo',
    message: '你好'
});
// result.code 状态码
// result.msg 消息
// result.data.message 回复内容
2
3
4
5
6
7
8
# logInfo
- 参数
- label: 日志标签
- data: 日志数据(可选)
 
- 返回
- void: 无返回值
 
写入信息日志
focusany.logInfo('日志标签', { data: '数据' });
# logError
- 参数
- label: 错误标签
- data: 错误数据(可选)
 
- 返回
- void: 无返回值
 
写入错误日志
focusany.logError('错误标签', { error: '错误信息' });
# logPath
- 参数
- 无
 
- 返回
- Promise<string>: 日志文件路径
 
获取日志文件路径
const logPath = await focusany.logPath();
# logShow
- 参数
- 无
 
- 返回
- void: 无返回值
 
显示日志文件
focusany.logShow();
# addLaunch 添加启动
- 参数
- keyword: 关键字
- name: 名称
- hotkey: 热键配置- key: 按键
- modifiers: 修饰键数组
 
 
- 返回
- Promise<void>: 无返回值
 
添加启动项
await focusany.addLaunch('test', '测试应用', {
    key: 'T',
    modifiers: ['Control', 'Shift']
});
2
3
4
# removeLaunch 移除启动
- 参数
- keywords: 关键字
 
- 返回
- void: 无返回值
 
移除启动项
focusany.removeLaunch('test');
# activateLatestWindow 激活最新窗口
- 参数
- 无
 
- 返回
- Promise<void>: 无返回值
 
激活最新使用的窗口
await focusany.activateLatestWindow();
# db
数据库操作
# db.put
- 参数
- doc: 文档对象(DbDoc类型)- _id: 文档ID
- _rev: 文档版本(可选)
 
 
- 返回
- DbReturn: 操作结果- id: 文档ID
- rev: 文档版本(可选)
- ok: 操作是否成功(可选)
- error: 是否有错误(可选)
- name: 错误名称(可选)
- message: 错误消息(可选)
 
 
添加文档
focusany.db.put(doc);
# db.get
- 参数
- id: 文档ID
 
- 返回
- DbDoc<T> | null: 文档对象或null
 
获取文档
focusany.db.get(id);
# db.remove
- 参数
- doc: 文档ID字符串或文档对象
 
- 返回
- DbReturn: 操作结果
 
删除文档
focusany.db.remove(doc);
# db.bulkDocs
- 参数
- docs: 文档对象数组
 
- 返回
- DbReturn[]: 操作结果数组
 
批量添加文档
focusany.db.bulkDocs(docs);
# db.allDocs
- 参数
- key: 键名(可选)
 
- 返回
- DbDoc<T>[]: 文档数组
 
批量获取文档
focusany.db.allDocs(key);
# db.postAttachment
- 参数
- docId: 文档ID
- attachment: 附件数据(Uint8Array)
- type: 附件类型
 
- 返回
- DbReturn: 操作结果
 
保存附件
focusany.db.postAttachment(docId, attachment, type);
# db.getAttachment
- 参数
- docId: 文档ID
 
- 返回
- Uint8Array | null: 附件数据或null
 
获取附件
focusany.db.getAttachment(docId);
# db.getAttachmentType
- 参数
- docId: 文档ID
 
- 返回
- string | null: 附件类型或null
 
获取附件类型
focusany.db.getAttachmentType(docId);
# dbStorage
本地存储
# dbStorage.setItem
- 参数
- key: 存储键名
- value: 存储值
 
- 返回
- void: 无返回值
 
设置存储
focusany.dbStorage.setItem('key', 'value');
focusany.dbStorage.setItem('key', { data: 'object' });
2
# dbStorage.getItem
- 参数
- key: 存储键名
 
- 返回
- T: 存储的值
 
获取存储
const value = focusany.dbStorage.getItem('key');
const object = focusany.dbStorage.getItem('key');
2
# dbStorage.removeItem
- 参数
- key: 存储键名
 
- 返回
- void: 无返回值
 
移除存储
focusany.dbStorage.removeItem('key');
# setRemoteWebRuntime
- 参数
- info: 运行时信息- userAgent: 用户代理字符串
- urlMap: URL映射对象
- types: 类型数组
- domains: 域名数组
- blocks: 阻止列表数组
 
 
- 返回
- Promise<undefined>: 无返回值
 
设置远程Web运行时
await focusany.setRemoteWebRuntime({
    userAgent: 'Mozilla/5.0...',
    urlMap: {
        'example.com': 'https://proxy.example.com'
    },
    types: ['text/html', 'application/json'],
    domains: ['example.com', 'api.example.com'],
    blocks: ['ads.example.com']
});
2
3
4
5
6
7
8
9
# file
文件操作
# file.exists
- 参数
- path: 文件或目录路径
 
- 返回
- Promise<boolean>: 是否存在
 
判断文件或目录是否存在
const exists = await focusany.file.exists('/path/to/file.txt');
# file.read
- 参数
- path: 文件路径
 
- 返回
- Promise<string>: 文件内容
 
读取文件内容
const content = await focusany.file.read('/path/to/file.txt');
# file.write
- 参数
- path: 文件路径
- data: 文件内容
 
- 返回
- Promise<void>: 无返回值
 
写入文件内容
await focusany.file.write('/path/to/file.txt', 'file content');
# file.remove
- 参数
- path: 文件或目录路径
 
- 返回
- Promise<void>: 无返回值
 
删除文件或目录
await focusany.file.remove('/path/to/file.txt');
# file.ext
- 参数
- path: 文件路径
 
- 返回
- Promise<string>: 文件扩展名
 
获取文件后缀
const ext = await focusany.file.ext('/path/to/file.txt'); // 返回 '.txt'
# file.writeTemp
- 参数
- ext: 文件扩展名
- data: 文件数据,支持字符串或Uint8Array
- option: 选项(可选)- isBase64: 是否为Base64数据(可选)
 
 
- 返回
- Promise<string>: 临时文件路径
 
保存文件到临时路径
const tempPath = await focusany.file.writeTemp('txt', 'file content');
const tempPath2 = await focusany.file.writeTemp('png', base64Data, { isBase64: true });
2
# fad
快捷文件操作
# fad.read
- 参数
- type: 文件类型
- path: 文件路径
 
- 返回
- Promise<any>: 文件内容
 
读取快捷文件内容
const data = await focusany.fad.read('type', '/path/to/file');
# fad.write
- 参数
- type: 文件类型
- path: 文件路径
- data: 文件数据
 
- 返回
- Promise<void>: 无返回值
 
写入快捷文件内容
await focusany.fad.write('type', '/path/to/file', { data: 'content' });
# view
智能区域
# view.setHeight
- 参数
- height: 高度(像素)
 
- 返回
- void: 无返回值
 
设置快捷面板当前插件渲染区域的高度
focusany.view.setHeight(300);
# view.getHeight
- 参数
- 无
 
- 返回
- Promise<number>: 当前高度
 
获取快捷面板当前插件渲染区域的高度
const height = await focusany.view.getHeight();
# detach
分离窗口
# detach.setTitle
- 参数
- title: 窗口标题
 
- 返回
- void: 无返回值
 
设置分离窗口的标题
focusany.detach.setTitle('窗口标题');
# detach.setOperates
- 参数
- operates: 操作按钮数组- name: 操作名称
- title: 操作标题
- click: 点击回调函数
 
 
- 返回
- void: 无返回值
 
设置分离窗口的操作按钮
focusany.detach.setOperates([
    {
        name: 'save',
        title: '保存',
        click: () => {
            console.log('保存按钮点击');
        }
    },
    {
        name: 'close',
        title: '关闭',
        click: () => {
            console.log('关闭按钮点击');
        }
    }
]);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# detach.setPosition
- 参数
- position: 窗口位置,可选值:- "center"|- "right-bottom"|- "left-top"|- "right-top"|- "left-bottom"
 
- 返回
- void: 无返回值
 
设置分离窗口的位置
// 可选位置: 'center' | 'right-bottom' | 'left-top' | 'right-top' | 'left-bottom'
focusany.detach.setPosition('center');
2
# detach.setAlwaysOnTop
- 参数
- alwaysOnTop: 是否置顶
 
- 返回
- void: 无返回值
 
设置分离窗口是否置顶
focusany.detach.setAlwaysOnTop(true);
# detach.setSize
- 参数
- width: 窗口宽度
- height: 窗口高度
 
- 返回
- void: 无返回值
 
设置分离窗口的大小
focusany.detach.setSize(800, 600);
# util
工具类
# util.randomString
- 参数
- length: 随机字符串长度
 
- 返回
- string: 随机字符串
 
生成随机字符串
const randomStr = focusany.util.randomString(10);
# util.bufferToBase64
- 参数
- buffer: Uint8Array类型的数据
 
- 返回
- string: Base64编码字符串
 
Buffer 转 Base64
const base64 = focusany.util.bufferToBase64(buffer);
# util.base64ToBuffer
- 参数
- base64: Base64编码字符串
 
- 返回
- Uint8Array: Buffer数据
 
Base64 转 Buffer
const buffer = focusany.util.base64ToBuffer('base64string');
# util.datetimeString
- 参数
- 无
 
- 返回
- string: 当前时间戳字符串
 
获取当前时间戳字符串
const datetime = focusany.util.datetimeString();
# util.base64Encode
- 参数
- data: 要编码的数据
 
- 返回
- string: Base64编码字符串
 
数据转 Base64
const encoded = focusany.util.base64Encode({ data: 'test' });
# util.base64Decode
- 参数
- data: Base64编码字符串
 
- 返回
- any: 解码后的数据
 
Base64 转数据
const decoded = focusany.util.base64Decode('encodedString');
# util.md5
- 参数
- data: 要计算MD5的字符串
 
- 返回
- string: MD5哈希值
 
MD5 摘要
const hash = focusany.util.md5('input string');
# util.save
- 参数
- filename: 文件名
- data: 文件数据,支持字符串或Uint8Array
- option: 选项(可选)- isBase64: 是否为Base64数据(可选)
 
 
- 返回
- boolean: 保存是否成功
 
保存文件
// 保存文本文件
focusany.util.save('filename.txt', 'text content');
// 保存Base64数据
focusany.util.save('filename.png', 'base64data', { isBase64: true });
// 保存Buffer数据
focusany.util.save('filename.bin', bufferData);
2
3
4
5
6
7
8