本指南将帮助你快速上手 ZerOS 程序开发,了解 ZerOS 的开发思维和最佳实践。
ZerOS 程序开发遵循以下核心思维:
进程生命周期管理
ProcessManager 进行生命周期管理__init__、__exit__、__info__ 三个必需方法ProcessManager 调用资源管理
__exit__ 中清理ProcessManager.allocateMemory 分配内存GUIManager 管理窗口(推荐)权限系统
__info__ 中声明所需权限用户控制系统
root 拥有系统最高权限D:/cache/ 目录UserControl API 进行用户管理锁屏界面
Ctrl + L 快捷键手动锁定屏幕system/assets/start/ 目录随机选择模块化设计
ZerOS 支持两种程序类型:
在 system/service/DISK/D/application/ 目录下创建你的程序目录:
system/service/DISK/D/application/
└── myapp/
├── myapp.js # 主程序文件(必需)
├── myapp.css # 样式文件(可选)
└── myapp.svg # 图标文件(可选)
// system/service/DISK/D/application/myapp/myapp.js
(function(window) {
'use strict';
const PROGRAM_NAME = 'MYAPP';
const MYAPP = {
pid: null,
window: null,
__init__: async function(pid, initArgs) {
this.pid = pid;
// 获取 GUI 容器
const guiContainer = initArgs.guiContainer || document.getElementById('gui-container');
// 创建窗口
this.window = document.createElement('div');
this.window.className = 'myapp-window zos-gui-window';
this.window.dataset.pid = pid.toString();
// 注册到 GUIManager
if (typeof GUIManager !== 'undefined') {
GUIManager.registerWindow(pid, this.window, {
title: '我的应用',
icon: 'application/myapp/myapp.svg',
onClose: () => {
// onClose 回调只用于执行清理工作,不应调用 unregisterWindow 或 _closeWindow
// 窗口关闭流程由 GUIManager 统一管理
// GUIManager 会在窗口关闭后自动检查该 PID 是否还有其他窗口
// 如果没有且不是 Exploit 程序(PID 10000),会自动 kill 进程
// 这样可以确保程序多实例(不同 PID)互不影响
}
});
}
// 添加到容器
guiContainer.appendChild(this.window);
},
__exit__: async function() {
if (typeof GUIManager !== 'undefined') {
if (this.windowId) {
GUIManager.unregisterWindow(this.windowId);
} else if (this.pid) {
GUIManager.unregisterWindow(this.pid);
}
} else if (this.window && this.window.parentElement) {
this.window.parentElement.removeChild(this.window);
}
},
__info__: function() {
return {
name: 'myapp',
type: 'GUI',
version: '1.0.0',
description: '我的应用程序',
author: 'Your Name',
copyright: '© 2024',
permissions: typeof PermissionManager !== 'undefined' ? [
PermissionManager.PERMISSION.GUI_WINDOW_CREATE
] : [],
metadata: {
allowMultipleInstances: true
}
};
}
};
// 导出到全局作用域
if (typeof window !== 'undefined') {
window[PROGRAM_NAME] = MYAPP;
} else if (typeof globalThis !== 'undefined') {
globalThis[PROGRAM_NAME] = MYAPP;
}
})(typeof window !== 'undefined' ? window : globalThis);
在 kernel/process/applicationAssets.js 中注册你的程序:
const APPLICATION_ASSETS = {
"myapp": {
script: "application/myapp/myapp.js",
styles: ["application/myapp/myapp.css"],
icon: "application/myapp/myapp.svg",
metadata: {
autoStart: false,
priority: 1,
description: "我的应用程序",
version: "1.0.0",
type: "GUI",
allowMultipleInstances: true
}
}
};
程序可以通过以下方式启动:
ProcessManager.startProgram('myapp', {}) 启动autoStart: true,系统启动时自动运行ZerOS 系统要求所有程序必须遵守以下开发规范,以确保系统稳定运行和资源正确管理。
所有事件处理必须通过内核的 EventManager 进行统一管理
// ✅ 正确:使用 EventManager
EventManager.registerEventHandler(this.pid, 'click', (e, eventContext) => {
// 处理点击事件
// 可以使用 eventContext.stopPropagation() 控制事件传播
}, {
priority: 100,
selector: '.my-button'
});
// 对于非冒泡事件(如 mouseenter, mouseleave, load, error)
EventManager.registerElementEvent(this.pid, element, 'mouseenter', (e) => {
// 处理鼠标进入事件
});
// ❌ 错误:直接使用 addEventListener(会被警告,不推荐)
element.addEventListener('click', handler);
为什么必须使用 EventManager:
eventContext API 控制事件传播详细说明:请参考 EventManager API 文档
所有日志输出必须通过内核的 KernelLogger 进行统一管理
// ✅ 正确:使用 KernelLogger
KernelLogger.info('MYAPP', '程序启动');
KernelLogger.warn('MYAPP', '警告信息');
KernelLogger.error('MYAPP', '错误信息', error);
KernelLogger.debug('MYAPP', '调试信息');
// ❌ 错误:直接使用 console.log(不推荐)
console.log('程序启动');
console.warn('警告信息');
console.error('错误信息');
为什么必须使用 KernelLogger:
详细说明:请参考 KernelLogger API 文档
GUI 程序必须使用 GUIManager 进行窗口管理
// ✅ 正确:使用 GUIManager
GUIManager.registerWindow(this.pid, this.window, {
title: '我的应用',
icon: 'application/myapp/myapp.svg',
onClose: () => {
// onClose 回调只用于执行清理工作,不应调用 unregisterWindow 或 _closeWindow
// 窗口关闭流程由 GUIManager 统一管理
// GUIManager 会在窗口关闭后自动检查该 PID 是否还有其他窗口
// 如果没有且不是 Exploit 程序(PID 10000),会自动 kill 进程
},
onMinimize: () => {
// 窗口最小化回调
},
onMaximize: (isMaximized) => {
// 窗口最大化回调,isMaximized 为 true 表示最大化,false 表示还原
}
});
// ❌ 错误:手动管理窗口(不推荐)
this.window.style.position = 'fixed';
this.window.style.left = '100px';
this.window.style.top = '100px';
// 手动实现拖动、拉伸等功能
为什么必须使用 GUIManager:
窗口关闭回调注意事项:
onClose 回调只用于执行清理工作,不应调用 unregisterWindow 或 _closeWindow详细说明:请参考 GUIManager API 文档
所有内核 API 调用都需要相应权限,程序必须在 __info__ 中声明所需权限
// ✅ 正确:在 __info__ 中声明权限
__info__: function() {
return {
name: 'myapp',
type: 'GUI',
version: '1.0.0',
description: '我的应用程序',
author: 'Your Name',
copyright: '© 2024',
permissions: typeof PermissionManager !== 'undefined' ? [
PermissionManager.PERMISSION.GUI_WINDOW_CREATE, // 创建窗口(普通权限,自动授予)
PermissionManager.PERMISSION.EVENT_LISTENER, // 注册事件(普通权限,自动授予)
PermissionManager.PERMISSION.KERNEL_DISK_READ, // 读取文件(普通权限,自动授予)
PermissionManager.PERMISSION.KERNEL_DISK_WRITE, // 写入文件(特殊权限,需要用户确认)
PermissionManager.PERMISSION.KERNEL_DISK_CREATE, // 创建文件/目录(特殊权限,需要用户确认)
PermissionManager.PERMISSION.KERNEL_DISK_DELETE, // 删除文件/目录(特殊权限,需要用户确认)
PermissionManager.PERMISSION.KERNEL_DISK_LIST, // 列出目录(普通权限,自动授予)
PermissionManager.PERMISSION.SYSTEM_NOTIFICATION, // 显示通知(普通权限,自动授予)
PermissionManager.PERMISSION.SYSTEM_STORAGE_READ, // 读取系统存储
PermissionManager.PERMISSION.SYSTEM_STORAGE_WRITE, // 写入系统存储
PermissionManager.PERMISSION.CRYPT_GENERATE_KEY, // 生成密钥
PermissionManager.PERMISSION.CRYPT_ENCRYPT, // 加密
PermissionManager.PERMISSION.CRYPT_DECRYPT, // 解密
PermissionManager.PERMISSION.CRYPT_MD5, // MD5 哈希
PermissionManager.PERMISSION.CRYPT_RANDOM // 随机数生成
] : [],
metadata: {
allowMultipleInstances: true
}
};
}
为什么必须声明权限:
详细说明:请参考 PermissionManager API 文档
程序必须在 __exit__ 中清理所有资源
// ✅ 正确:完整清理所有资源
__exit__: async function() {
try {
// 1. 取消注册 GUI 窗口(优先处理,确保窗口正确关闭)
if (this.windowId && typeof GUIManager !== 'undefined') {
await GUIManager.unregisterWindow(this.windowId);
} else if (this.pid && typeof GUIManager !== 'undefined') {
await GUIManager.unregisterWindow(this.pid);
}
// 2. 取消注册上下文菜单(如果注册了自定义菜单)
if (this.pid && typeof ContextMenuManager !== 'undefined') {
ContextMenuManager.unregisterContextMenu(this.pid);
}
// 3. EventManager 会自动清理所有事件监听器
// 但如果有直接使用 addEventListener 的,需要手动清理
if (this._manualEventListeners) {
this._manualEventListeners.forEach(({element, event, handler}) => {
if (element && typeof element.removeEventListener === 'function') {
element.removeEventListener(event, handler);
}
});
this._manualEventListeners = null;
}
// 4. 清理 DOM 元素(从 DOM 中移除)
if (this.window && this.window.parentElement) {
this.window.parentElement.removeChild(this.window);
}
// 5. 清理定时器和异步操作
if (this._timers) {
this._timers.forEach(timer => clearTimeout(timer));
this._timers = null;
}
// 6. 释放内存引用
if (this.memoryRefs) {
for (const [refId, ref] of this.memoryRefs) {
if (typeof ProcessManager !== 'undefined') {
await ProcessManager.freeMemoryRef(this.pid, refId);
}
}
this.memoryRefs.clear();
this.memoryRefs = null;
}
// 7. 清理所有对象引用(帮助垃圾回收)
this.window = null;
this.windowId = null;
this._eventHandlers = null;
this._timers = null;
this.memoryRefs = null;
} catch (error) {
if (typeof KernelLogger !== 'undefined') {
KernelLogger.error("MYAPP", `清理资源失败: ${error.message}`, error);
} else {
console.error('清理资源失败:', error);
}
}
}
为什么必须清理资源:
详细说明:请参考 最佳实践 - 资源清理
程序必须禁止自动初始化,等待 ProcessManager 调用
// ❌ 错误:自动初始化
(function() {
const app = new MyApp();
app.init(); // 这会在脚本加载时立即执行
})();
// ✅ 正确:等待 ProcessManager 调用
const MYAPP = {
__init__: async function(pid, initArgs) {
// 初始化代码
}
};
所有程序创建的 DOM 元素必须标记 data-pid 属性
// ✅ 正确:标记 data-pid
const element = document.createElement('div');
element.dataset.pid = this.pid.toString();
始终使用 try-catch 处理异步操作
// ✅ 正确:错误处理
__init__: async function(pid, initArgs) {
try {
await this._initialize();
} catch (error) {
if (typeof KernelLogger !== 'undefined') {
KernelLogger.error('MYAPP', `初始化失败: ${error.message}`, error);
}
// 清理已创建的资源
await this.__exit__();
}
}
重要: 程序必须禁止自动初始化,包括:
正确做法:
// ❌ 错误:自动初始化
(function() {
const app = new MyApp();
app.init();
})();
// ✅ 正确:等待 ProcessManager 调用
const MYAPP = {
__init__: async function(pid, initArgs) {
// 初始化代码
}
};
程序必须导出为全局对象,命名规则:程序名全大写。
// 程序名: myapp
// 导出对象名: MYAPP
const MYAPP = {
__init__: async function(pid, initArgs) { /* ... */ },
__exit__: async function() { /* ... */ },
__info__: function() { /* ... */ }
};
所有程序创建的 DOM 元素必须标记 data-pid 属性:
const element = document.createElement('div');
element.dataset.pid = this.pid.toString();
始终使用 try-catch 处理异步操作:
__init__: async function(pid, initArgs) {
try {
await this._initialize();
} catch (error) {
console.error('初始化失败:', error);
// 清理已创建的资源
}
}
__init__(pid, initArgs)程序初始化方法,由 ProcessManager 在程序启动时调用。
参数:
pid (number): 进程 ID,由 ProcessManager 分配initArgs (Object): 初始化参数对象
{
pid: number, // 进程 ID
args: Array, // 命令行参数
env: Object, // 环境变量
cwd: string, // 当前工作目录(如 "C:")
terminal: Object, // 终端实例(仅 CLI 程序)
guiContainer: HTMLElement, // GUI 容器(仅 GUI 程序)
metadata: Object, // 元数据
}
返回值: Promise<void>
__exit__()程序退出方法,由 ProcessManager 在程序关闭时调用。
职责:
返回值: Promise<void>
重要提示:
GUIManager.unregisterWindow() 取消注册窗口ContextMenuManager.unregisterContextMenu() 取消注册__info__()程序信息方法,返回程序的元数据。
返回值: Object
必需字段:
name (string): 程序名称type (string): 程序类型,'GUI' 或 'CLI'version (string): 版本号description (string): 程序描述author (string): 作者copyright (string): 版权信息可选字段:
permissions (Array): 所需权限列表metadata (Object): 额外元数据
allowMultipleInstances (boolean): 是否支持多实例GUI 程序必须将 UI 渲染到指定的容器中:
__init__: async function(pid, initArgs) {
this.pid = pid;
// 获取 GUI 容器
const guiContainer = initArgs.guiContainer || document.getElementById('gui-container');
// 创建窗口元素
this.window = document.createElement('div');
this.window.className = 'myapp-window zos-gui-window';
this.window.dataset.pid = pid.toString();
// 注册到 GUIManager(推荐)
if (typeof GUIManager !== 'undefined') {
GUIManager.registerWindow(pid, this.window, {
title: '我的应用',
icon: 'application/myapp/myapp.svg',
onClose: () => {
// onClose 回调只用于执行清理工作,不应调用 unregisterWindow 或 _closeWindow
// 窗口关闭流程由 GUIManager 统一管理
// GUIManager 会在窗口关闭后自动检查该 PID 是否还有其他窗口
// 如果没有且不是 Exploit 程序(PID 10000),会自动 kill 进程
}
});
}
// 添加到容器
guiContainer.appendChild(this.window);
}
在 CSS 中使用主题变量,确保程序能够响应主题切换:
.myapp-window {
background: var(--theme-background-elevated, rgba(37, 43, 53, 0.98));
border: 1px solid var(--theme-border, rgba(139, 92, 246, 0.3));
color: var(--theme-text, #d7e0dd);
}
.myapp-button {
background: var(--theme-primary, #8b5cf6);
color: var(--theme-text-on-primary, #ffffff);
}
.myapp-button:hover {
background: var(--theme-primary-hover, #7c3aed);
}
推荐使用 GUIManager,窗口的拖动、拉伸、最小化、最大化等功能会自动处理。GUIManager 会自动:
如果需要自定义窗口控制,可以使用 EventManager:
// 注册拖动事件(不推荐,GUIManager 已自动处理)
EventManager.registerDrag(
`myapp-window-${this.pid}`,
titleBar,
this.window,
this.windowState,
(e) => { /* 拖动开始 */ },
(e) => { /* 拖动中 */ },
(e) => { /* 拖动结束 */ },
['.button', '.controls']
);
注意:如果使用 GUIManager,通常不需要手动注册拖动和拉伸事件,GUIManager 会自动处理。
详细 API 文档请参考 EventManager API 和 GUIManager API
CLI 程序通过 initArgs.terminal 获取终端实例:
__init__: async function(pid, initArgs) {
this.pid = pid;
this.terminal = initArgs.terminal;
if (!this.terminal) {
throw new Error('CLI程序需要终端环境');
}
// 使用终端 API
this.terminal.write('Hello from CLI program\n');
this.terminal.setCwd('C:/Users');
}
对于存放在 D:/bin/ 目录下的 CLI 程序(如 ps.js、ping.js),需要特别注意 __init__ 方法的实现方式。
重要原则:
__init__ 方法应该立即返回,不要等待异步操作完成setTimeout() 延迟执行实际的命令逻辑__init__ 返回后将程序状态设置为 runningsetTimeout 的回调执行时,程序状态已经是 running 了正确示例:
__init__: async function(pid, initArgs = {}) {
this.pid = pid;
this.terminal = initArgs.terminal;
if (!this.terminal) {
throw new Error('程序需要终端环境');
}
// 保存参数供后续使用
const args = initArgs.args || [];
// 使用 setTimeout 延迟执行命令逻辑
// 这样 __init__ 可以立即返回,进程管理器会将状态设置为 running
// 然后 setTimeout 回调执行时,状态已经是 running 了
setTimeout(async () => {
try {
// 在这里执行实际的命令逻辑
// 此时程序状态已经是 running
// 解析参数
// 执行命令
// 输出结果
// 执行完成后,延迟关闭程序
setTimeout(async () => {
await this._selfClose();
}, 300);
} catch (error) {
// 错误处理
setTimeout(async () => {
await this._selfClose();
}, 300);
}
}, 0); // 使用 0ms 延迟,确保在下一个事件循环中执行
}
错误示例(不要这样做):
__init__: async function(pid, initArgs = {}) {
// ❌ 错误:等待异步操作会阻止 __init__ 返回
await this._waitForRunning(); // 不要这样做!
// ❌ 错误:直接执行命令逻辑会阻止 __init__ 返回
await this._executeCommand(); // 不要这样做!
}
为什么需要这样做:
__init__ 执行完成后才会将程序状态设置为 running__init__ 内部有异步等待,会导致 __init__ 无法及时返回__init__ 的返回setTimeout 可以确保 __init__ 立即返回,同时命令逻辑在状态变为 running 后执行通过共享空间访问终端 API:
// 获取终端 API
const TerminalAPI = POOL.__GET__("APPLICATION_SHARED_POOL", "TerminalAPI");
if (TerminalAPI) {
// 写入输出
TerminalAPI.write('Hello\n');
// 写入带样式的文本
TerminalAPI.write({
text: 'Error: File not found\n',
color: 'red',
bold: true
});
// 清空输出
TerminalAPI.clear();
// 设置工作目录
TerminalAPI.setCwd('C:/Users');
// 获取环境变量
const env = TerminalAPI.getEnv();
// 设置环境变量
TerminalAPI.setEnv({ KEY: 'value' });
// 创建标签页
const tabId = TerminalAPI.createTab('My Tab');
// 注册命令处理器
TerminalAPI.onCommand((command) => {
if (command === 'hello') {
TerminalAPI.write('Hello from my CLI program!\n');
}
});
}
详细 API 文档请参考 TerminalAPI 文档
__init__: async function(pid, initArgs) {
const args = initArgs.args || [];
// 解析参数
if (args.length > 0) {
const filename = args[0];
// 处理文件
}
}
CLI 程序可以通过以下方式被终端执行:
applicationAssets.js 中注册程序,终端可以直接通过程序名执行D:/bin/<程序名>.js,终端会自动查找并执行示例:
// 方式1: 在 applicationAssets.js 中注册
// 终端输入: myapp
// 方式2: 将文件放在 D:/bin/myapp.js
// 终端输入: myapp(会自动查找 D:/bin/myapp.js)
// 方式3: 设置环境变量
// export myapp "D:/application/myapp/myapp.js"
// 终端输入: myapp(会执行环境变量值对应的程序)
注意:
D:/bin/ 目录时,文件必须是有效的 ZerOS 程序(包含 __init__ 和 __info__ 方法)CLI 程序可以通过终端命令管理系统环境变量:
env - 列出所有环境变量setenv <name> <value> - 设置环境变量(需要管理员权限)export <name>=<value> - 设置环境变量(需要管理员权限)unsetenv <name> - 删除环境变量(需要管理员权限)getenv <name> - 获取环境变量值注意:
LStorage 的注册表中(system.registry.environment)详细命令列表请参考 终端命令参考
ZerOS 提供了完整的用户控制系统,支持多用户管理、权限级别控制和用户认证。
系统支持三种用户级别:
UserControl.USER_LEVEL.USER): 普通用户,无法授权高风险权限UserControl.USER_LEVEL.ADMIN): 管理员,拥有完全控制权限UserControl.USER_LEVEL.DEFAULT_ADMIN): 默认管理员(系统最高权限),默认用户名为 root// 获取当前登录的用户名
const currentUser = UserControl.getCurrentUser();
// 获取当前用户的级别
const level = UserControl.getCurrentUserLevel();
// 检查是否为管理员
if (UserControl.isAdmin()) {
console.log('当前用户是管理员');
}
// 无密码用户登录
const success = await UserControl.login('root');
// 有密码用户登录
const success = await UserControl.login('TestUser', 'password123');
// 检查用户是否有密码
const hasPassword = UserControl.hasPassword('TestUser');
// 设置用户密码(管理员可以设置任何用户的密码)
await UserControl.setPassword('TestUser', 'newpassword123');
// 非管理员用户修改自己的密码(需要提供当前密码)
await UserControl.setPassword('TestUser', 'newpassword123', 'oldpassword');
// 设置用户头像(头像文件应已存在于 D:/cache/ 目录)
await UserControl.setAvatar('root', 'avatar_root_1234567890.jpg');
// 获取用户头像路径
const avatarPath = UserControl.getAvatarPath('root');
// 列出所有用户
const users = UserControl.listUsers();
console.log('所有用户:', users);
// [
// { username: 'root', level: 'DEFAULT_ADMIN', hasPassword: false, avatar: null },
// { username: 'TestUser', level: 'USER', hasPassword: true, avatar: 'avatar_TestUser_1234567890.jpg' }
// ]
普通用户无法授权高风险权限(如加密相关权限),只有管理员可以授权所有权限:
// 检查权限是否为高风险权限
const isHighRisk = UserControl.isHighRiskPermission('CRYPT_GENERATE_KEY');
// 检查用户级别是否可以授权指定级别的权限
const canGrant = UserControl.canGrantPermission(
UserControl.USER_LEVEL.USER,
'DANGEROUS'
);
系统启动时会显示 Windows 11 风格的锁屏界面,用户需要登录后才能进入桌面。
可以通过 Ctrl + L 快捷键手动锁定屏幕:
// 手动锁定屏幕(内部方法,通常通过快捷键调用)
TaskbarManager._lockScreen();
system/assets/start/ 目录随机选择背景图片(可开关)锁屏相关设置存储在 LStorage 中:
// 随机锁屏壁纸开关
system.lockscreenRandomBg: boolean // 默认 true
// 自定义锁屏背景路径
system.lockscreenBackground: string // 当随机壁纸关闭时使用
// 时间组件开关
system.lockscreenTimeComponent: boolean // 默认 true
// 每日一言组件开关
system.lockscreenDailyQuote: boolean // 默认 true
每日一言使用 CacheDrive 进行缓存管理:
// 缓存键
const cacheKey = 'system.dailyQuote';
// 读取缓存
const cachedQuote = await ProcessManager.callKernelAPI(
ProcessManager.EXPLOIT_PID,
'Cache.get',
[{ key: cacheKey }]
);
// 保存到缓存
await ProcessManager.callKernelAPI(
ProcessManager.EXPLOIT_PID,
'Cache.set',
[{ key: cacheKey, value: quote, options: { ttl: 0 } }]
);
// 删除缓存
await ProcessManager.callKernelAPI(
ProcessManager.EXPLOIT_PID,
'Cache.delete',
[{ key: cacheKey }]
);
缓存策略:
系统提供了内置的"设置"程序(可通过 Ctrl + X 快捷键启动),支持:
设置程序使用 Windows 10 风格的 UI,并自动适配主题切换。
ZerOS 提供了基于 Web Speech API 的语音识别功能,支持多语言识别、持续识别和实时结果反馈。
使用语音识别功能需要 SPEECH_RECOGNITION 权限(特殊权限,需要用户确认):
__info__: function() {
return {
// ...
permissions: ['SPEECH_RECOGNITION']
};
}
__init__: async function(pid, initArgs) {
this.pid = pid;
// 1. 检查浏览器支持
const supported = await Process.callKernelAPI('Speech.isSupported');
if (!supported) {
alert('浏览器不支持语音识别');
return;
}
// 2. 创建识别会话
await Process.callKernelAPI('Speech.createSession', [{
language: 'zh-CN', // 简体中文
continuous: true, // 持续识别
interimResults: true, // 返回临时结果
onResult: (text, isFinal) => {
if (isFinal) {
console.log('最终结果:', text);
this.handleFinalResult(text);
} else {
console.log('临时结果:', text);
this.updateTemporaryResult(text);
}
},
onError: (error) => {
console.error('识别错误:', error);
alert('识别出错: ' + error.message);
},
onEnd: () => {
console.log('识别已结束');
}
}]);
// 3. 启动识别
await Process.callKernelAPI('Speech.startRecognition');
}
// 处理最终结果
handleFinalResult: function(text) {
// 更新 UI 显示最终结果
const resultElement = document.getElementById('result');
if (resultElement) {
resultElement.textContent = text;
}
}
// 更新临时结果
updateTemporaryResult: function(text) {
// 更新 UI 显示临时结果(灰色、斜体等)
const tempElement = document.getElementById('temp-result');
if (tempElement) {
tempElement.textContent = text;
tempElement.style.opacity = '0.6';
tempElement.style.fontStyle = 'italic';
}
}
__exit__: async function() {
// 停止并销毁识别会话
try {
await Process.callKernelAPI('Speech.stopSession');
} catch (error) {
console.error('停止识别失败:', error);
}
}
// 停止识别(但保留会话)
await Process.callKernelAPI('Speech.stopRecognition');
// 重新启动识别
await Process.callKernelAPI('Speech.startRecognition');
// 获取会话状态
const status = await Process.callKernelAPI('Speech.getSessionStatus');
console.log('识别状态:', status.status);
console.log('识别语言:', status.language);
console.log('结果数量:', status.resultsCount);
// 获取所有最终结果
const results = await Process.callKernelAPI('Speech.getSessionResults');
console.log('所有结果:', results);
语音识别支持多种语言,默认使用简体中文(zh-CN):
zh-CN - 简体中文(默认)zh-TW - 繁体中文en-US - 美式英语en-GB - 英式英语ja-JP - 日语ko-KR - 韩语fr-FR - 法语de-DE - 德语es-ES - 西班牙语ru-RU - 俄语continuous: true,识别停止后会自动重启class VoiceAssistant {
async __init__(pid, initArgs) {
this.pid = pid;
this.isListening = false;
this.results = [];
// 检查支持
const supported = await Process.callKernelAPI('Speech.isSupported');
if (!supported) {
this.showError('浏览器不支持语音识别');
return;
}
// 创建 UI
this.createUI();
// 创建识别会话
await this.setupRecognition();
}
createUI() {
const container = document.getElementById('gui-container');
this.window = document.createElement('div');
this.window.className = 'voice-assistant zos-gui-window';
this.window.innerHTML = `
<div class="status">未开始</div>
<div class="temp-result" style="opacity: 0.6; font-style: italic;"></div>
<div class="final-results"></div>
<button class="start-btn">开始识别</button>
<button class="stop-btn" disabled>停止识别</button>
`;
container.appendChild(this.window);
// 绑定事件
this.window.querySelector('.start-btn').addEventListener('click', () => this.start());
this.window.querySelector('.stop-btn').addEventListener('click', () => this.stop());
}
async setupRecognition() {
await Process.callKernelAPI('Speech.createSession', [{
language: 'zh-CN',
continuous: true,
interimResults: true,
onResult: (text, isFinal) => {
if (isFinal) {
this.results.push(text);
this.updateFinalResults();
} else {
this.updateTemporaryResult(text);
}
},
onError: (error) => {
this.showError('识别错误: ' + error.message);
this.stop();
}
}]);
}
async start() {
try {
await Process.callKernelAPI('Speech.startRecognition');
this.isListening = true;
this.window.querySelector('.status').textContent = '正在识别...';
this.window.querySelector('.start-btn').disabled = true;
this.window.querySelector('.stop-btn').disabled = false;
} catch (error) {
this.showError('启动识别失败: ' + error.message);
}
}
async stop() {
try {
await Process.callKernelAPI('Speech.stopRecognition');
this.isListening = false;
this.window.querySelector('.status').textContent = '已停止';
this.window.querySelector('.start-btn').disabled = false;
this.window.querySelector('.stop-btn').disabled = true;
} catch (error) {
this.showError('停止识别失败: ' + error.message);
}
}
updateTemporaryResult(text) {
const tempElement = this.window.querySelector('.temp-result');
tempElement.textContent = text;
}
updateFinalResults() {
const resultsElement = this.window.querySelector('.final-results');
resultsElement.innerHTML = this.results.map((r, i) =>
`<div class="result-item">${i + 1}. ${r}</div>`
).join('');
}
showError(message) {
alert(message);
}
async __exit__() {
if (this.isListening) {
await this.stop();
}
await Process.callKernelAPI('Speech.stopSession');
if (this.window && this.window.parentElement) {
this.window.parentElement.removeChild(this.window);
}
}
}
更多详细信息请参考 SpeechDrive API 文档。
ZerOS 提供了丰富的 CSS 变量,用于主题和样式管理。详细变量列表请参考 ThemeManager API
背景颜色:
--theme-background: 主背景色--theme-background-secondary: 次要背景色--theme-background-elevated: 提升的背景色(用于窗口)文本颜色:
--theme-text: 主文本色--theme-text-secondary: 次要文本色--theme-text-muted: 弱化文本色主题色:
--theme-primary: 主色调--theme-primary-light: 浅主色调--theme-primary-dark: 深主色调--theme-primary-hover: 悬停主色调程序可以监听主题变更,动态更新 UI:
// 监听主题变更
if (typeof ThemeManager !== 'undefined') {
ThemeManager.onThemeChange((themeId, theme) => {
// 更新程序 UI
this._updateTheme(theme);
});
ThemeManager.onStyleChange((styleId, style) => {
// 更新程序样式
this._updateStyle(style);
});
}
// 设置本地 GIF 动图作为背景
await ThemeManager.setLocalImageAsBackground('D:/images/background.gif');
// 设置本地静态图片作为背景
await ThemeManager.setLocalImageAsBackground('D:/images/wallpaper.jpg');
详细 API 文档请参考 ThemeManager API
重要: 程序绝对不能自动初始化。所有初始化代码必须在 __init__ 方法中执行。
所有程序创建的 DOM 元素必须标记 data-pid 属性。
始终使用 try-catch 处理异步操作。
异常报告:对于严重错误,可以使用异常处理管理器报告异常:
// 报告程序异常(程序将被自动终止)
try {
await someCriticalOperation();
} catch (error) {
await KernelAPI.call('Exception.report', [
'PROGRAM',
`程序崩溃: ${error.message}`,
{
errorCode: 'CRASH_001',
stack: error.stack,
timestamp: Date.now()
}
]);
// 程序将被自动终止
}
// 报告服务异常(仅记录日志,不影响系统运行)
try {
await networkService.connect();
} catch (error) {
await KernelAPI.call('Exception.report', [
'SERVICE',
'网络服务连接失败',
{
service: 'NetworkService',
endpoint: endpoint,
error: error.message
}
]);
}
异常等级说明:
详细说明请参考 ExceptionHandler API 文档
在 __exit__ 中清理所有资源,确保没有内存泄漏:
__exit__: async function() {
try {
// 1. 取消注册 GUI 窗口(优先处理,确保窗口正确关闭)
if (this.windowId && typeof GUIManager !== 'undefined') {
await GUIManager.unregisterWindow(this.windowId);
} else if (this.pid && typeof GUIManager !== 'undefined') {
// 如果没有 windowId,尝试使用 pid
await GUIManager.unregisterWindow(this.pid);
}
// 2. 取消注册上下文菜单(如果注册了自定义菜单)
if (this.pid && typeof ContextMenuManager !== 'undefined') {
ContextMenuManager.unregisterContextMenu(this.pid);
}
// 3. 移除所有事件监听器
if (this._eventHandlers && Array.isArray(this._eventHandlers)) {
this._eventHandlers.forEach(({ element, event, handler }) => {
if (element && typeof element.removeEventListener === 'function') {
element.removeEventListener(event, handler);
}
});
this._eventHandlers = null;
}
// 4. 清理 DOM 元素(从 DOM 中移除)
if (this.window && this.window.parentElement) {
this.window.parentElement.removeChild(this.window);
}
// 5. 清理定时器和异步操作
if (this._timers) {
this._timers.forEach(timer => clearTimeout(timer));
this._timers = null;
}
// 6. 释放内存引用
if (this.memoryRefs) {
for (const [refId, ref] of this.memoryRefs) {
if (typeof ProcessManager !== 'undefined') {
await ProcessManager.freeMemoryRef(this.pid, refId);
}
}
this.memoryRefs.clear();
this.memoryRefs = null;
}
// 7. 清理所有对象引用(帮助垃圾回收)
this.window = null;
this.windowId = null;
this._eventHandlers = null;
this._timers = null;
this.memoryRefs = null;
// ... 清理其他引用
} catch (error) {
if (typeof KernelLogger !== 'undefined') {
KernelLogger.error("MYAPP", `清理资源失败: ${error.message}`, error);
} else {
console.error('清理资源失败:', error);
}
}
}
关键要点:
GUIManager.unregisterWindow() 确保窗口正确关闭ProcessManager.freeMemoryRef() 释放分配的内存在 __exit__ 中清理所有资源:
__exit__: async function() {
// 清理 DOM
if (this.window && this.window.parentElement) {
this.window.parentElement.removeChild(this.window);
}
// 取消事件监听器
if (this.eventListeners) {
this.eventListeners.forEach(({element, event, handler}) => {
element.removeEventListener(event, handler);
});
this.eventListeners = [];
}
// 释放内存
if (this.memoryRefs) {
for (const [refId, ref] of this.memoryRefs) {
await ProcessManager.freeMemoryRef(this.pid, refId);
}
this.memoryRefs.clear();
}
// 注销窗口
if (typeof GUIManager !== 'undefined') {
if (this.windowId) {
GUIManager.unregisterWindow(this.windowId);
} else if (this.pid) {
GUIManager.unregisterWindow(this.pid);
}
}
}
在 CSS 中使用主题变量,确保程序能够响应主题切换。
推荐使用 GUIManager 管理窗口,获得统一的窗口管理功能。
__init__ 和 __exit__ 必须是异步函数。
如果程序支持多实例,在 __info__ 中声明:
__info__: function() {
return {
// ...
metadata: {
allowMultipleInstances: true
}
};
}
GUI 程序必须将 UI 渲染到 initArgs.guiContainer 中。
程序间通信应使用共享空间:
// 设置共享数据
const sharedSpace = ProcessManager.getSharedSpace();
sharedSpace.setData('myKey', { data: 'value' });
// 获取共享数据
const data = sharedSpace.getData('myKey');
// system/service/DISK/D/application/myapp/myapp.js
(function(window) {
'use strict';
const PROGRAM_NAME = 'MYAPP';
const MYAPP = {
pid: null,
window: null,
windowState: null,
eventListeners: [],
memoryRefs: new Map(),
__init__: async function(pid, initArgs) {
this.pid = pid;
try {
// 获取 GUI 容器
const guiContainer = initArgs.guiContainer || document.getElementById('gui-container');
// 创建窗口元素
this.window = document.createElement('div');
this.window.className = 'myapp-window zos-gui-window';
this.window.dataset.pid = pid.toString();
this.window.style.cssText = `
position: fixed;
width: 800px;
height: 600px;
background: var(--theme-background-elevated, rgba(37, 43, 53, 0.98));
border: 1px solid var(--theme-border, rgba(139, 92, 246, 0.3));
border-radius: var(--style-window-border-radius, 12px);
box-shadow: var(--style-window-box-shadow-focused, 0 12px 40px rgba(0, 0, 0, 0.5));
backdrop-filter: var(--style-window-backdrop-filter, blur(30px) saturate(180%));
color: var(--theme-text, #d7e0dd);
`;
// 注册到 GUIManager
if (typeof GUIManager !== 'undefined') {
GUIManager.registerWindow(pid, this.window, {
title: '我的应用',
icon: 'application/myapp/myapp.svg',
onClose: () => {
// onClose 回调只用于执行清理工作,不应调用 unregisterWindow 或 _closeWindow
// 窗口关闭流程由 GUIManager 统一管理
// GUIManager 会在窗口关闭后自动检查该 PID 是否还有其他窗口
// 如果没有且不是 Exploit 程序(PID 10000),会自动 kill 进程
// 这样可以确保程序多实例(不同 PID)互不影响
}
});
}
// 创建内容
const content = document.createElement('div');
content.textContent = 'Hello, ZerOS!';
content.style.cssText = 'padding: 20px;';
this.window.appendChild(content);
// 注册事件处理程序(必须使用 EventManager)
if (typeof EventManager !== 'undefined') {
EventManager.registerEventHandler(this.pid, 'click', (e, eventContext) => {
if (e.target.classList.contains('my-button')) {
// 处理按钮点击
if (typeof KernelLogger !== 'undefined') {
KernelLogger.info('MYAPP', '按钮被点击');
}
}
}, {
priority: 100,
selector: '.my-button'
});
}
// 添加到容器
guiContainer.appendChild(this.window);
// 初始化窗口状态
this.windowState = {
isFullscreen: false,
isDragging: false,
isResizing: false
};
} catch (error) {
// 使用 KernelLogger 记录错误(必须使用)
if (typeof KernelLogger !== 'undefined') {
KernelLogger.error('MYAPP', `初始化失败: ${error.message}`, error);
} else {
console.error('初始化失败:', error);
}
if (this.window && this.window.parentElement) {
this.window.parentElement.removeChild(this.window);
}
throw error;
}
},
__exit__: async function() {
try {
// 1. 注销窗口(优先处理,确保窗口正确关闭)
if (typeof GUIManager !== 'undefined') {
if (this.windowId) {
await GUIManager.unregisterWindow(this.windowId);
} else if (this.pid) {
await GUIManager.unregisterWindow(this.pid);
}
} else if (this.window && this.window.parentElement) {
this.window.parentElement.removeChild(this.window);
}
// 2. EventManager 会自动清理所有通过它注册的事件监听器
// 但如果有直接使用 addEventListener 的,需要手动清理
if (this._manualEventListeners) {
this._manualEventListeners.forEach(({element, event, handler}) => {
if (element && typeof element.removeEventListener === 'function') {
element.removeEventListener(event, handler);
}
});
this._manualEventListeners = null;
}
// 3. 释放内存
if (this.memoryRefs) {
for (const [refId, ref] of this.memoryRefs) {
if (typeof ProcessManager !== 'undefined') {
await ProcessManager.freeMemoryRef(this.pid, refId);
}
}
this.memoryRefs.clear();
this.memoryRefs = null;
}
// 4. 清理所有对象引用
this.window = null;
this.windowId = null;
} catch (error) {
if (typeof KernelLogger !== 'undefined') {
KernelLogger.error('MYAPP', `清理资源失败: ${error.message}`, error);
} else {
console.error('清理资源失败:', error);
}
}
},
__info__: function() {
return {
name: 'myapp',
type: 'GUI',
version: '1.0.0',
description: '我的应用程序示例',
author: 'Your Name',
copyright: '© 2024',
permissions: typeof PermissionManager !== 'undefined' ? [
PermissionManager.PERMISSION.GUI_WINDOW_CREATE
] : [],
metadata: {
allowMultipleInstances: true
}
};
}
};
// 导出到全局作用域
if (typeof window !== 'undefined') {
window[PROGRAM_NAME] = MYAPP;
} else if (typeof globalThis !== 'undefined') {
globalThis[PROGRAM_NAME] = MYAPP;
}
})(typeof window !== 'undefined' ? window : globalThis);
// system/service/DISK/D/application/mycli/mycli.js
(function(window) {
'use strict';
const PROGRAM_NAME = 'MYCLI';
const MYCLI = {
pid: null,
terminal: null,
__init__: async function(pid, initArgs) {
this.pid = pid;
this.terminal = initArgs.terminal;
if (!this.terminal) {
throw new Error('CLI程序需要终端环境');
}
// 获取命令行参数
const args = initArgs.args || [];
// 输出欢迎信息
this.terminal.write('MyCLI v1.0.0\n');
this.terminal.write('Type "help" for help\n');
// 处理参数
if (args.length > 0) {
const filename = args[0];
this.terminal.write(`Processing file: ${filename}\n`);
// 处理文件
}
},
__exit__: async function() {
// CLI 程序清理
if (this.terminal) {
this.terminal.write('MyCLI exited\n');
}
},
__info__: function() {
return {
name: 'mycli',
type: 'CLI',
version: '1.0.0',
description: '我的CLI程序示例',
author: 'Your Name',
copyright: '© 2024',
metadata: {
allowMultipleInstances: false
}
};
}
};
// 导出到全局作用域
if (typeof window !== 'undefined') {
window[PROGRAM_NAME] = MYCLI;
} else if (typeof globalThis !== 'undefined') {
globalThis[PROGRAM_NAME] = MYCLI;
}
})(typeof window !== 'undefined' ? window : globalThis);
// system/service/DISK/D/bin/mycommand.js
(function(window) {
'use strict';
const MYCOMMAND = {
pid: null,
terminal: null,
_closing: false,
__init__: async function(pid, initArgs = {}) {
this.pid = pid;
this.terminal = initArgs.terminal;
if (!this.terminal) {
throw new Error('程序需要终端环境');
}
// 保存参数供后续使用
const args = initArgs.args || [];
// ⚠️ 重要:使用 setTimeout 延迟执行命令逻辑
// 这样 __init__ 可以立即返回,进程管理器会将状态设置为 running
// 然后 setTimeout 回调执行时,状态已经是 running 了
setTimeout(async () => {
try {
// 此时程序状态已经是 running,可以安全执行命令逻辑
// 检查帮助选项
if (args.includes('-h') || args.includes('--help')) {
this._showUsage();
setTimeout(async () => {
await this._selfClose();
}, 300);
return;
}
// 执行实际命令逻辑
await this._executeCommand(args);
// 确保所有输出都已完成,然后延迟关闭
await new Promise(resolve => setTimeout(resolve, 200));
setTimeout(async () => {
await this._selfClose();
}, 300);
} catch (error) {
if (typeof KernelLogger !== 'undefined') {
KernelLogger.error("MYCOMMAND", `执行命令失败: ${error.message}`, error);
}
// 错误情况下也延迟关闭
await new Promise(resolve => setTimeout(resolve, 200));
setTimeout(async () => {
await this._selfClose();
}, 300);
}
}, 0); // 使用 0ms 延迟,确保在下一个事件循环中执行
},
_executeCommand: async function(args) {
// 执行实际的命令逻辑
this.terminal.write('执行命令...\n');
// ...
},
_showUsage: function() {
this.terminal.write('用法: mycommand [选项]\n');
this.terminal.write('选项:\n');
this.terminal.write(' -h, --help 显示帮助信息\n');
},
_selfClose: async function() {
// 防止重复调用
if (this._closing) {
return;
}
this._closing = true;
// 延迟一小段时间,确保所有输出都已完成
await new Promise(resolve => setTimeout(resolve, 200));
// 检查 PID 是否存在
if (!this.pid) {
return;
}
// 使用 ProcessManager 的强制自终止 API
let ProcessMgr = null;
if (typeof ProcessManager !== 'undefined') {
ProcessMgr = ProcessManager;
} else if (typeof POOL !== 'undefined' && typeof POOL.__GET__ === 'function') {
try {
ProcessMgr = POOL.__GET__('KERNEL_GLOBAL_POOL', 'ProcessManager');
} catch (e) {
// 忽略错误
}
}
if (ProcessMgr) {
try {
// 优先通过内核 API 调用 requestSelfTermination(强制自终止)
if (typeof ProcessMgr.callKernelAPI === 'function') {
await ProcessMgr.callKernelAPI(this.pid, 'Process.requestSelfTermination', []);
} else if (typeof ProcessMgr.requestSelfTermination === 'function') {
await ProcessMgr.requestSelfTermination(this.pid);
} else if (typeof ProcessMgr.killProgram === 'function') {
await ProcessMgr.killProgram(this.pid, true);
}
} catch (error) {
// 如果所有方法都失败,尝试强制关闭
if (typeof ProcessMgr.killProgram === 'function') {
try {
await ProcessMgr.killProgram(this.pid, true);
} catch (forceError) {
// 忽略强制关闭失败
}
}
}
}
},
__exit__: async function() {
// 清理资源
this.terminal = null;
},
__info__: function() {
return {
name: 'MYCOMMAND',
type: 'CLI',
version: '1.0.0',
description: '我的命令行工具',
author: 'ZerOS Team',
copyright: '© 2025 ZerOS',
permissions: typeof PermissionManager !== 'undefined' ? [
PermissionManager.PERMISSION.EVENT_LISTENER
] : [],
metadata: {
autoStart: false,
priority: 1,
allowMultipleInstances: true
}
};
}
};
// 注册到全局
if (typeof window !== 'undefined') {
window.MYCOMMAND = MYCOMMAND;
}
// 注册到 POOL(如果可用)
if (typeof POOL !== 'undefined' && typeof POOL.__ADD__ === 'function') {
try {
if (!POOL.__HAS__("APPLICATION_SHARED_POOL")) {
POOL.__INIT__("APPLICATION_SHARED_POOL");
}
POOL.__ADD__("APPLICATION_SHARED_POOL", "MYCOMMAND", MYCOMMAND);
} catch (e) {
if (typeof KernelLogger !== 'undefined') {
KernelLogger.error("MYCOMMAND", `注册到 POOL 失败: ${e.message}`, e);
}
}
}
})(window);
A: 使用浏览器开发者工具(F12)查看控制台日志。ZerOS 使用 KernelLogger 记录日志,可以通过 ProcessManager.setLogLevel() 设置日志级别。
A: 检查以下几点:
__init__, __exit__, __info__ 方法applicationAssets.js 中注册了程序A: 通过 POOL 共享空间获取:
const otherProgramAPI = POOL.__GET__("APPLICATION_SHARED_POOL", "OtherProgramAPI");
if (otherProgramAPI) {
otherProgramAPI.someMethod();
}
A: 必须使用 EventManager。所有事件处理都应该通过 EventManager 进行统一管理:
// ✅ 正确:使用 EventManager
EventManager.registerEventHandler(this.pid, 'click', (e, eventContext) => {
// 处理点击事件
}, {
priority: 100,
selector: '.my-button'
});
// ❌ 错误:直接使用 addEventListener(会被警告)
element.addEventListener('click', handler);
详细说明请参考 EventManager API 文档
A: 使用 Disk API 保存到文件系统,或使用 LStorage API:
// 使用 Disk API
await Disk.writeFile('C:/Users/username/data.json', JSON.stringify(data));
// 使用 LStorage API
await LStorage.setProgramStorage(this.pid, 'settings', { theme: 'dark' });
A: 使用 ProcessManager.startProgram 启动文件管理器,并传入选择器模式参数:
// 选择单个文件
await ProcessManager.startProgram('filemanager', {
args: [],
mode: 'file-selector',
onFileSelected: async (fileItem) => {
if (fileItem && fileItem.path) {
console.log('选择的文件:', fileItem.path);
// 处理选择的文件
}
}
});
// 选择单个文件夹
await ProcessManager.startProgram('filemanager', {
args: [],
mode: 'folder-selector',
onFolderSelected: async (folderItem) => {
if (folderItem && folderItem.path) {
console.log('选择的文件夹:', folderItem.path);
// 处理选择的文件夹
}
}
});
// 多选文件/文件夹(支持同时选择多个文件和文件夹)
await ProcessManager.startProgram('filemanager', {
args: [],
mode: 'file-selector', // 或 'folder-selector'
multiSelect: true, // 启用多选
onMultipleSelected: async (selectedItems) => {
// selectedItems 是一个数组,包含所有选中的项目
console.log('选择了', selectedItems.length, '个项目');
selectedItems.forEach(item => {
console.log('-', item.path, item.type); // type: 'file' 或 'directory'
});
// 处理选中的多个项目
}
});
注意事项:
file-selector 模式下,多选时可以选择文件和文件夹folder-selector 模式下,多选时只能选择文件夹A: 在 __info__ 的 metadata 中设置 allowMultipleInstances: true。注意:每个实例都有独立的 PID。
A: PID 在 __init__ 方法中作为第一个参数传入,应该保存到 this.pid:
__init__: async function(pid, initArgs) {
this.pid = pid; // 保存 PID
// ...
}
A: 使用 typeof 检查:
if (typeof GUIManager !== 'undefined') {
// GUIManager 可用
await GUIManager.registerWindow(this.pid, this.window);
} else {
console.warn('GUIManager 不可用');
}
A: 始终使用 try-catch 包裹异步操作:
try {
const result = await Disk.readFile('C:/data.txt');
console.log(result);
} catch (error) {
console.error('读取文件失败:', error);
// 显示用户友好的错误提示
if (typeof GUIManager !== 'undefined') {
await GUIManager.showAlert('读取文件失败: ' + error.message, '错误', 'error');
}
}
A: 使用 CSS 变量,并在主题切换时更新:
.my-element {
background: var(--theme-bg-primary);
color: var(--theme-text-primary);
border: 1px solid var(--theme-border-color);
}
主题变量由 ThemeManager 管理,程序无需手动设置。
A: 使用 GUIManager 的窗口管理功能,窗口标题栏自动支持拖拽。如果需要自定义拖拽区域,可以监听鼠标事件:
let isDragging = false;
let dragOffset = { x: 0, y: 0 };
element.addEventListener('mousedown', (e) => {
isDragging = true;
dragOffset.x = e.clientX - element.offsetLeft;
dragOffset.y = e.clientY - element.offsetTop;
});
document.addEventListener('mousemove', (e) => {
if (isDragging) {
element.style.left = (e.clientX - dragOffset.x) + 'px';
element.style.top = (e.clientY - dragOffset.y) + 'px';
}
});
document.addEventListener('mouseup', () => {
isDragging = false;
});
A: 使用 Disk API 或后端服务(推荐使用 SystemInformation 构建URL):
// 使用 Disk API(推荐)
const content = await Disk.readFile('D:/data.txt');
await Disk.writeFile('D:/data.txt', '新内容');
// 使用 SystemInformation 构建服务URL(推荐,自动适配后端类型)
const url = (typeof SystemInformation !== 'undefined' && SystemInformation.buildServiceUrlObject)
? SystemInformation.buildServiceUrlObject(SystemInformation.SERVICE_NAMES.FSDIRVE)
: new URL('/system/service/FSDirve.php', window.location.origin);
url.searchParams.set('action', 'read_file');
url.searchParams.set('path', 'D:/');
url.searchParams.set('fileName', 'data.txt');
const response = await fetch(url.toString());
const result = await response.json();
if (result.status === 'success') {
console.log(result.data.content);
}
A: 使用 CompressionDrive API:
// 压缩单个文件或目录
await CompressionDrive.compressZip(
'D:/source/file.txt',
'D:/backup/archive.zip'
);
// 压缩多个文件/目录
await CompressionDrive.compressZip(
['D:/file1.txt', 'D:/dir1', 'D:/dir2'],
'D:/backup/multi.zip'
);
// 解压缩
await CompressionDrive.extractZip(
'D:/backup/archive.zip',
'D:/extracted',
{ overwrite: true }
);
// 查看 ZIP 内容
const list = await CompressionDrive.listZip('D:/backup/archive.zip');
console.log(`包含 ${list.fileCount} 个文件`);
A: 使用后端服务的 check_path_exists 操作(推荐使用 SystemInformation):
const url = (typeof SystemInformation !== 'undefined' && SystemInformation.buildServiceUrlObject)
? SystemInformation.buildServiceUrlObject(SystemInformation.SERVICE_NAMES.FSDIRVE)
: new URL('/system/service/FSDirve.php', window.location.origin);
url.searchParams.set('action', 'check_path_exists');
url.searchParams.set('path', 'D:/data.txt');
const response = await fetch(url.toString());
const result = await response.json();
if (result.status === 'success' && result.data.exists) {
console.log('文件存在');
}
A: 使用后端服务(推荐使用 SystemInformation):
// 创建目录
const url = (typeof SystemInformation !== 'undefined' && SystemInformation.buildServiceUrlObject)
? SystemInformation.buildServiceUrlObject(SystemInformation.SERVICE_NAMES.FSDIRVE)
: new URL('/system/service/FSDirve.php', window.location.origin);
url.searchParams.set('action', 'create_dir');
url.searchParams.set('path', 'D:/newdir');
await fetch(url.toString());
// 删除目录
url.searchParams.set('action', 'delete_dir');
url.searchParams.set('path', 'D:/newdir');
await fetch(url.toString());
A: 使用后端服务的 list_dir 操作(推荐使用 SystemInformation):
const url = (typeof SystemInformation !== 'undefined' && SystemInformation.buildServiceUrlObject)
? SystemInformation.buildServiceUrlObject(SystemInformation.SERVICE_NAMES.FSDIRVE)
: new URL('/system/service/FSDirve.php', window.location.origin);
url.searchParams.set('action', 'list_dir');
url.searchParams.set('path', 'D:/application');
const response = await fetch(url.toString());
const result = await response.json();
if (result.status === 'success') {
result.data.files.forEach(file => {
console.log(file.name, file.type); // type: 'file' 或 'directory'
});
}
A: 文件管理器会自动识别 ZIP 文件,双击会使用 ziper 程序打开。在程序中也可以手动启动:
await ProcessManager.startProgram('ziper', {
args: ['D:/archive.zip'] // ZIP 文件路径
});
A: 使用 NotificationManager:
if (typeof NotificationManager !== 'undefined') {
await NotificationManager.show({
title: '操作完成',
message: '文件已成功保存',
type: 'success', // 'info', 'success', 'warning', 'error'
duration: 3000
});
}
A: 使用 GUIManager:
if (typeof GUIManager !== 'undefined') {
const confirmed = await GUIManager.showConfirm(
'确定要删除这个文件吗?',
'确认删除',
'warning'
);
if (confirmed) {
// 执行删除操作
}
}
A: 使用 ThemeManager:
if (typeof ThemeManager !== 'undefined') {
const theme = ThemeManager.getCurrentTheme();
console.log('当前主题:', theme.name);
console.log('主题变量:', theme.variables);
}
A: 对于大文件,建议:
// 显示加载状态
button.disabled = true;
button.textContent = '处理中...';
try {
// 执行大文件操作
await processLargeFile('D:/largefile.zip');
button.textContent = '完成';
} catch (error) {
button.textContent = '失败';
console.error(error);
} finally {
button.disabled = false;
}
A: 监听拖拽事件:
element.addEventListener('dragover', (e) => {
e.preventDefault();
element.classList.add('drag-over');
});
element.addEventListener('drop', async (e) => {
e.preventDefault();
element.classList.remove('drag-over');
const files = e.dataTransfer.files;
for (const file of files) {
// 读取文件内容
const reader = new FileReader();
reader.onload = async (event) => {
const content = event.target.result;
// 保存到虚拟文件系统
await Disk.writeFile(`D:/uploads/${file.name}`, content);
};
reader.readAsText(file);
}
});
A: 使用 POOL 共享空间:
// 程序 A:设置共享数据
const sharedSpace = ProcessManager.getSharedSpace();
sharedSpace.setData('MYAPP_DATA', { key: 'value' });
// 程序 B:获取共享数据
const sharedSpace = ProcessManager.getSharedSpace();
const data = sharedSpace.getData('MYAPP_DATA');
A: 检查响应状态和内容类型:
try {
const response = await fetch(url.toString());
// 检查响应类型
const contentType = response.headers.get('content-type') || '';
let result;
if (contentType.includes('application/json')) {
result = await response.json();
} else {
const text = await response.text();
throw new Error(`服务端返回非 JSON 响应: ${text.substring(0, 100)}`);
}
// 检查 HTTP 状态码
if (!response.ok) {
throw new Error(result.message || `HTTP ${response.status}`);
}
if (result.status === 'success') {
// 处理成功响应
} else {
throw new Error(result.message || '操作失败');
}
} catch (error) {
console.error('请求失败:', error);
// 显示错误提示
}
A: 建议:
// 防抖示例
function debounce(func, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
const debouncedSearch = debounce((query) => {
performSearch(query);
}, 300);
A: 检查以下几点:
__exit__ 中被移除__exit__: async function() {
// 清理事件监听器
this._eventHandlers.forEach(({element, event, handler}) => {
element.removeEventListener(event, handler);
});
// 清理定时器
if (this._timers) {
this._timers.forEach(timer => clearTimeout(timer));
}
// 清理引用
this.window = null;
this._eventHandlers = null;
this._timers = null;
}
A: 使用 ProcessManager 的路径转换功能:
// 虚拟路径转实际 URL
if (typeof ProcessManager !== 'undefined' &&
typeof ProcessManager.convertVirtualPathToUrl === 'function') {
const url = ProcessManager.convertVirtualPathToUrl('D:/application/icon.svg');
// 返回: http://localhost:8089/system/service/DISK/D/application/icon.svg
}
A: 使用 ContextMenuManager:
if (typeof ContextMenuManager !== 'undefined') {
ContextMenuManager.registerContextMenu(this.pid, {
selector: '.my-element',
items: [
{
label: '复制',
icon: 'copy.svg',
action: () => {
console.log('复制');
}
},
{
label: '删除',
icon: 'trash.svg',
action: () => {
console.log('删除');
}
}
]
});
}
A: 使用 GUIManager 的窗口管理功能:
// 注册窗口时设置回调
GUIManager.registerWindow(this.pid, this.window, {
onMinimize: () => {
console.log('窗口已最小化');
},
onMaximize: (isMaximized) => {
console.log('窗口状态:', isMaximized ? '最大化' : '还原');
}
});
A: 使用 try-catch 和错误边界:
__init__: async function(pid, initArgs) {
try {
// 初始化代码
await this._initialize();
} catch (error) {
console.error('初始化失败:', error);
// 显示错误提示
if (typeof GUIManager !== 'undefined') {
await GUIManager.showAlert(
`程序初始化失败: ${error.message}`,
'错误',
'error'
);
}
// 清理已创建的资源
await this.__exit__();
// 退出程序
if (typeof ProcessManager !== 'undefined') {
ProcessManager.killProgram(this.pid);
}
}
}
A: 可以通过网络请求检查版本:
async function checkUpdate() {
try {
const response = await fetch('https://api.example.com/version');
const latestVersion = await response.json();
const currentVersion = this.__info__().version;
if (latestVersion > currentVersion) {
if (typeof GUIManager !== 'undefined') {
const update = await GUIManager.showConfirm(
`发现新版本 ${latestVersion},是否更新?`,
'更新提示',
'info'
);
if (update) {
// 执行更新逻辑
}
}
}
} catch (error) {
console.error('检查更新失败:', error);
}
}
A: 通过 ProcessManager 调用加密 API,需要相应权限:
// 在 __info__ 中声明权限
__info__() {
return {
// ...
permissions: [
PermissionManager.PERMISSION.CRYPT_GENERATE_KEY,
PermissionManager.PERMISSION.CRYPT_ENCRYPT,
PermissionManager.PERMISSION.CRYPT_DECRYPT,
PermissionManager.PERMISSION.CRYPT_MD5,
PermissionManager.PERMISSION.CRYPT_RANDOM
]
};
}
// 生成密钥对
const keyPair = await ProcessManager.callKernelAPI(
this.pid,
'Crypt.generateKeyPair',
[{ keySize: 2048, setAsDefault: true }]
);
// 加密数据
const encrypted = await ProcessManager.callKernelAPI(
this.pid,
'Crypt.encrypt',
['敏感数据']
);
// 解密数据
const decrypted = await ProcessManager.callKernelAPI(
this.pid,
'Crypt.decrypt',
[encrypted]
);
// MD5 哈希
const hash = await ProcessManager.callKernelAPI(
this.pid,
'Crypt.md5',
['数据']
);
// 生成随机数
const randomInt = await ProcessManager.callKernelAPI(
this.pid,
'Crypt.randomInt',
[1, 100]
);
const randomString = await ProcessManager.callKernelAPI(
this.pid,
'Crypt.randomString',
[16]
);
详细文档请参考 CryptDrive API。
A: 使用 LStorage API:
// 保存设置
await LStorage.setProgramStorage(this.pid, 'settings', {
theme: 'dark',
language: 'zh-CN',
autoSave: true
});
// 读取设置
const settings = await LStorage.getProgramStorage(this.pid, 'settings') || {
theme: 'light',
language: 'zh-CN',
autoSave: false
};
A: 文件管理器会根据扩展名自动识别文件类型。在程序中也可以手动识别:
function getFileType(fileName) {
const ext = fileName.split('.').pop()?.toLowerCase() || '';
const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'svg'];
const codeExts = ['js', 'ts', 'html', 'css', 'json'];
if (imageExts.includes(ext)) return 'IMAGE';
if (codeExts.includes(ext)) return 'CODE';
if (ext === 'zip' || ext === 'rar') return 'ZIP';
return 'BINARY';
}
A: 必须使用 KernelLogger。所有日志输出都应该通过 KernelLogger 进行统一管理:
// ✅ 正确:使用 KernelLogger
if (typeof KernelLogger !== 'undefined') {
KernelLogger.info('MYAPP', '程序启动');
KernelLogger.warn('MYAPP', '警告信息');
KernelLogger.error('MYAPP', '错误信息', error);
KernelLogger.debug('MYAPP', '调试信息');
}
// ❌ 错误:直接使用 console.log(不推荐)
console.log('程序启动');
详细说明请参考 KernelLogger API 文档
A: 权限系统会自动处理。首次使用需要权限的 API 时,系统会提示用户授权:
// 使用需要权限的 API
try {
await Disk.writeFile('C:/system/file.txt', 'content');
} catch (error) {
if (error.message.includes('权限')) {
// 权限被拒绝
console.log('用户拒绝了权限请求');
}
}
A: 检查以下几点:
__info__() {
return {
permissions: [
PermissionManager.PERMISSION.EVENT_LISTENER
]
};
}
// ✅ 正确
EventManager.registerEventHandler(this.pid, 'click', handler);
// ❌ 错误(会被警告)
element.addEventListener('click', handler);
A: 在 __exit__ 方法中使用 EventManager.unregisterAllHandlersForPid:
__exit__: async function() {
// 清理所有事件监听器
if (typeof EventManager !== 'undefined') {
EventManager.unregisterAllHandlersForPid(this.pid);
}
// 清理窗口
if (this.windowId && typeof GUIManager !== 'undefined') {
GUIManager.unregisterWindow(this.windowId);
}
}
A: 确保使用 GUIManager.registerWindow 注册窗口,窗口会自动获得拖动和拉伸功能:
// GUIManager 会自动处理窗口拖动和拉伸
const windowInfo = GUIManager.registerWindow(this.pid, this.window, {
title: '我的程序',
icon: icon
});
如果窗口已经注册但拖动不工作,检查:
A: 使用 EventManager.registerDrag:
if (typeof EventManager !== 'undefined') {
EventManager.registerDrag(
`my-drag-${this.pid}`,
draggableElement, // 可拖动的元素
containerElement, // 容器元素
{ isDragging: false }, // 状态对象
(e) => {
// 拖动开始
state.isDragging = true;
},
(e) => {
// 拖动中
if (state.isDragging) {
// 更新元素位置
}
},
(e) => {
// 拖动结束
state.isDragging = false;
}
);
}
A: 对于窗口,GUIManager 会自动创建拉伸器。对于自定义元素,使用 EventManager.registerResizer:
if (typeof EventManager !== 'undefined') {
EventManager.registerResizer(
`my-resizer-${this.pid}`,
resizerElement, // 拉伸器元素
targetElement, // 目标元素
{ isResizing: false }, // 状态对象
(e) => {
// 拉伸开始
state.isResizing = true;
},
(e) => {
// 拉伸中
if (state.isResizing) {
// 更新元素大小
}
},
(e) => {
// 拉伸结束
state.isResizing = false;
}
);
}
A: 使用 GUIManager.getWindowInfo:
if (typeof GUIManager !== 'undefined' && this.windowId) {
const windowInfo = GUIManager.getWindowInfo(this.windowId);
if (windowInfo) {
console.log('窗口标题:', windowInfo.title);
console.log('是否最大化:', windowInfo.isMaximized);
console.log('是否最小化:', windowInfo.isMinimized);
console.log('z-index:', windowInfo.zIndex);
}
}
A: 使用 GUIManager.getFocusedWindowId:
if (typeof GUIManager !== 'undefined') {
const focusedWindowId = GUIManager.getFocusedWindowId();
if (focusedWindowId === this.windowId) {
console.log('当前窗口已获得焦点');
}
}
A: 使用 EventManager.registerEventHandler 监听 focus 和 blur 事件:
if (typeof EventManager !== 'undefined') {
EventManager.registerEventHandler(this.pid, 'focus', (e) => {
if (e.target === this.window) {
console.log('窗口获得焦点');
}
});
EventManager.registerEventHandler(this.pid, 'blur', (e) => {
if (e.target === this.window) {
console.log('窗口失去焦点');
}
});
}
A: 使用 GUIManager.showAlert、GUIManager.showConfirm 或 GUIManager.showPrompt:
// 提示框
await GUIManager.showAlert('操作完成', '提示', 'success');
// 确认框
const confirmed = await GUIManager.showConfirm(
'确定要删除吗?',
'确认删除',
'warning'
);
// 输入框
const input = await GUIManager.showPrompt(
'请输入文件名',
'输入',
'default.txt'
);
A: 使用 GUIManager.registerWindow 创建窗口,并设置合适的 z-index:
const dialogWindow = document.createElement('div');
dialogWindow.className = 'my-dialog zos-gui-window';
dialogWindow.style.cssText = `
width: 500px;
height: 400px;
display: flex;
flex-direction: column;
`;
const windowInfo = GUIManager.registerWindow(this.pid, dialogWindow, {
title: '自定义对话框',
icon: icon,
onClose: () => {
GUIManager.unregisterWindow(windowInfo.windowId);
}
});
// 聚焦窗口
GUIManager.focusWindow(windowInfo.windowId);
A: 使用 childWindows 数组管理多个窗口:
const MYAPP = {
pid: null,
window: null,
childWindows: [], // 子窗口列表
_openChildWindow: function(data) {
const childWindow = document.createElement('div');
childWindow.className = 'myapp-child-window zos-gui-window';
const windowInfo = GUIManager.registerWindow(this.pid, childWindow, {
title: '子窗口',
onClose: () => {
// 从列表中移除
const index = this.childWindows.findIndex(w => w.windowId === windowInfo.windowId);
if (index !== -1) {
this.childWindows.splice(index, 1);
}
GUIManager.unregisterWindow(windowInfo.windowId);
}
});
// 保存到列表
this.childWindows.push({
windowId: windowInfo.windowId,
window: childWindow,
windowInfo: windowInfo
});
GUIManager.focusWindow(windowInfo.windowId);
},
__exit__: async function() {
// 关闭所有子窗口
this.childWindows.forEach(child => {
if (child.windowId && typeof GUIManager !== 'undefined') {
GUIManager.unregisterWindow(child.windowId);
}
});
this.childWindows = [];
// 关闭主窗口
if (this.windowId && typeof GUIManager !== 'undefined') {
GUIManager.unregisterWindow(this.windowId);
}
}
};
A: 使用 POOL 共享空间:
// 程序 A:发布数据
if (typeof POOL !== 'undefined') {
if (!POOL.__HAS__("APPLICATION_SHARED_POOL")) {
POOL.__INIT__("APPLICATION_SHARED_POOL");
}
POOL.__ADD__("APPLICATION_SHARED_POOL", "MyAppData", {
value: 'some data',
update: (newValue) => {
// 更新数据
}
});
}
// 程序 B:获取数据
if (typeof POOL !== 'undefined') {
const myAppData = POOL.__GET__("APPLICATION_SHARED_POOL", "MyAppData");
if (myAppData) {
console.log(myAppData.value);
}
}
A: 使用 ProcessManager.callKernelAPI 调用 FileSystem API,它会自动处理路径规范化:
// ✅ 正确:使用 FileSystem API
const content = await ProcessManager.callKernelAPI(
this.pid,
'FileSystem.read',
['D:/path with spaces/file.txt']
);
// ❌ 错误:直接使用路径可能有问题
const url = `/system/service/FSDirve.php?path=D:/path with spaces/file.txt`;
A: 使用 FileSystem.list 或 FileSystem.read:
try {
// 尝试读取文件
await ProcessManager.callKernelAPI(
this.pid,
'FileSystem.read',
['D:/file.txt']
);
console.log('文件存在');
} catch (error) {
if (error.message.includes('不存在') || error.message.includes('not found')) {
console.log('文件不存在');
}
}
// 或者列出目录内容
try {
const list = await ProcessManager.callKernelAPI(
this.pid,
'FileSystem.list',
['D:/directory']
);
console.log('目录存在,包含', list.length, '个项目');
} catch (error) {
console.log('目录不存在');
}
A: 使用 HTML5 File API 和 FileSystem API:
// 创建文件输入元素
const input = document.createElement('input');
input.type = 'file';
input.multiple = true; // 支持多选
input.addEventListener('change', async (e) => {
const files = e.target.files;
for (const file of files) {
const reader = new FileReader();
reader.onload = async (event) => {
const content = event.target.result;
// 保存到虚拟文件系统
await ProcessManager.callKernelAPI(
this.pid,
'FileSystem.write',
[`D:/uploads/${file.name}`, content]
);
console.log(`文件 ${file.name} 已上传`);
};
reader.readAsText(file); // 或 readAsArrayBuffer 用于二进制文件
}
});
input.click();
A: 读取文件内容后创建下载链接:
async function downloadFile(virtualPath, fileName) {
try {
// 读取文件内容
const content = await ProcessManager.callKernelAPI(
this.pid,
'FileSystem.read',
[virtualPath]
);
// 创建 Blob
const blob = new Blob([content], { type: 'application/octet-stream' });
const url = URL.createObjectURL(blob);
// 创建下载链接
const a = document.createElement('a');
a.href = url;
a.download = fileName || virtualPath.split('/').pop();
a.click();
// 清理
URL.revokeObjectURL(url);
} catch (error) {
console.error('下载失败:', error);
if (typeof GUIManager !== 'undefined') {
await GUIManager.showAlert('下载失败: ' + error.message, '错误', 'error');
}
}
}
A: 检查版本并提示用户:
async function checkForUpdates() {
try {
// 获取当前版本
const currentVersion = this.__info__().version;
// 检查最新版本(从服务器或配置文件)
const response = await fetch('/system/service/version.json');
const versionInfo = await response.json();
if (versionInfo.latestVersion > currentVersion) {
const update = await GUIManager.showConfirm(
`发现新版本 ${versionInfo.latestVersion},是否更新?`,
'更新提示',
'info'
);
if (update) {
// 执行更新逻辑
// 例如:重新加载程序文件
window.location.reload();
}
}
} catch (error) {
KernelLogger.warn('MYAPP', '检查更新失败', error);
}
}
A: 使用 try-catch 和错误边界:
__init__: async function(pid, initArgs) {
this.pid = pid;
try {
await this._initialize();
} catch (error) {
KernelLogger.error('MYAPP', '初始化失败', error);
// 显示错误提示
if (typeof GUIManager !== 'undefined') {
await GUIManager.showAlert(
`程序启动失败: ${error.message}`,
'错误',
'error'
);
}
// 清理资源
await this.__exit__();
// 退出程序
if (typeof ProcessManager !== 'undefined') {
ProcessManager.killProgram(this.pid);
}
return;
}
}
_initialize: async function() {
// 初始化代码
// 如果出错,会抛出异常
}
A: 创建设置窗口并使用 LStorage 保存:
_openSettings: function() {
const settingsWindow = document.createElement('div');
settingsWindow.className = 'myapp-settings zos-gui-window';
// 加载当前设置
LStorage.getProgramStorage(this.pid, 'settings').then(settings => {
// 填充设置表单
const themeSelect = settingsWindow.querySelector('#theme-select');
themeSelect.value = settings?.theme || 'dark';
});
// 保存按钮
const saveBtn = settingsWindow.querySelector('#save-settings');
saveBtn.addEventListener('click', async () => {
const newSettings = {
theme: settingsWindow.querySelector('#theme-select').value,
// ... 其他设置
};
await LStorage.setProgramStorage(this.pid, 'settings', newSettings);
// 关闭设置窗口
GUIManager.unregisterWindow(settingsWindowInfo.windowId);
// 应用新设置
this._applySettings(newSettings);
});
const settingsWindowInfo = GUIManager.registerWindow(this.pid, settingsWindow, {
title: '设置',
onClose: () => {
GUIManager.unregisterWindow(settingsWindowInfo.windowId);
}
});
}
A: 使用 EventManager.registerEventHandler 监听键盘事件:
if (typeof EventManager !== 'undefined') {
EventManager.registerEventHandler(this.pid, 'keydown', (e, eventContext) => {
// Ctrl+S: 保存
if (e.ctrlKey && e.key === 's') {
e.preventDefault();
eventContext.preventDefault();
this._save();
}
// Ctrl+N: 新建
if (e.ctrlKey && e.key === 'n') {
e.preventDefault();
eventContext.preventDefault();
this._new();
}
// Escape: 关闭
if (e.key === 'Escape') {
if (this._hasUnsavedChanges()) {
// 提示保存
} else {
this._close();
}
}
}, {
priority: 50, // 较高优先级
useCapture: true
});
}
A: 使用 LStorage 或文件系统:
// 保存状态
async _saveState() {
const state = {
windowPosition: { x: this.window.style.left, y: this.window.style.top },
windowSize: { width: this.window.style.width, height: this.window.style.height },
userData: this.userData
};
await LStorage.setProgramStorage(this.pid, 'state', state);
}
// 恢复状态
async _restoreState() {
const state = await LStorage.getProgramStorage(this.pid, 'state');
if (state) {
if (state.windowPosition) {
this.window.style.left = state.windowPosition.x;
this.window.style.top = state.windowPosition.y;
}
if (state.windowSize) {
this.window.style.width = state.windowSize.width;
this.window.style.height = state.windowSize.height;
}
if (state.userData) {
this.userData = state.userData;
}
}
}
A: 使用配置文件和多语言支持:
const i18n = {
'zh-CN': {
'save': '保存',
'cancel': '取消',
'delete': '删除'
},
'en-US': {
'save': 'Save',
'cancel': 'Cancel',
'delete': 'Delete'
}
};
// 获取当前语言
_getLanguage: function() {
const settings = await LStorage.getProgramStorage(this.pid, 'settings');
return settings?.language || 'zh-CN';
}
// 翻译文本
_t: function(key) {
const lang = this._getLanguage();
return i18n[lang]?.[key] || key;
}
// 使用
button.textContent = this._t('save');
A: 使用 POOL 共享空间和事件系统:
// 主程序:注册插件接口
if (typeof POOL !== 'undefined') {
POOL.__ADD__("APPLICATION_SHARED_POOL", "MyAppPluginAPI", {
registerPlugin: (plugin) => {
this.plugins.push(plugin);
plugin.init?.(this);
},
unregisterPlugin: (pluginId) => {
this.plugins = this.plugins.filter(p => p.id !== pluginId);
}
});
}
// 插件:注册到主程序
const pluginAPI = POOL.__GET__("APPLICATION_SHARED_POOL", "MyAppPluginAPI");
if (pluginAPI) {
pluginAPI.registerPlugin({
id: 'my-plugin',
name: '我的插件',
init: (app) => {
// 插件初始化
}
});
}
示例程序: 查看 system/service/DISK/D/application/ 目录下的示例程序
terminal/: 终端程序示例vim/: 文本编辑器示例filemanager/: 文件管理器示例(支持选择器模式、多选功能)browser/: 浏览器示例ziper/: ZIP 压缩工具示例(支持多文件/目录压缩、ZIP 内容查看)内核模块: 查看 kernel/ 目录下的内核模块实现
API 文档: 查看 API 文档索引 获取完整的 API 参考
内核架构: 查看 内核架构文档 了解系统设计
祝开发愉快!
如有问题,请参考现有程序的实现或查看内核模块的源代码。