這是本文件的舊版!
本规范是非强制的,但强烈建议你遵守。
编程规范
为了能够配合既有代码使用,合理利用服务器资源,所有程序必须遵守本编程规范。
总旨
开放式电脑的程序需要基于事件驱动、能够“干净”地终止,做到低耦合高内聚、尽量运用库的功能,不要自己实现即有库已实现的功能。
具体来说,规则如下:
- 非后台程序中,使用event.pull系列函数处理事件。只有后台程序才可以使用event.listen函数。
- 无论是否为后台程序,键鼠事件必须使用event.pull系列函数处理。目的是为了退出程序后键鼠事件不再被处理。
- 如无特殊要求,使用local变量和函数。
- 必须能够处理interrupted事件,非后台程序中,处理的行为是注销所有事件、定时器、文件句柄等,然后退出整个程序;后台程序中,处理的行为是简单地退出。
- 后台程序中,必须监听一个事件。该事件触发后能注销所有事件、定时器、文件句柄等,从而“干净”地退出后台程序。
- 后台程序中,必须监听一个事件。该事件触发后能让后台程序恢复显示和处理键鼠事件。
示例
1.1 一个简单的前台程序
local timer = event.timer(1000, local function() -- 定时器 print("timer!"); end); while true do local id, _, x, y = event.pullMultiple("touch", "interrupted"); -- 中断事件 if id == "interrupted" then print("soft interrupt! exiting..."); event.cancel(timer); -- 清理资源 os.exit(0); -- 退出 -- 点击事件 elseif id == "touch" then print("user touched! x=", arg["x"], "; y=", arg["y"]); end end
1.2 一个稍微复杂的前台程序
local timer = event.timer(1000, local function() -- 定时器 print("timer!"); end); local ifTerminate = false; while true do -- 处理事件 event.pullFiltered(local function (ename, ...) local ename2handling = { -- 点击事件 ["touch"] = local function() print("user touched! x=", arg["x"], "; y=", arg["y"]); end, -- 红石事件 ["redstone_changed"] = local function() print("redstone changed! side=", arg["side"]); end, -- 中断事件 ["interrupted"] = local function() print("soft interrupt! closing..."); -- 这儿不能退出!在filter函数之中要返回true表示事件被处理了,然后在pullFiltered调用之外退出。 ifTerminate = true; -- 标记事件处理结束后退出 end }; if ename2handling[ename] then -- 这个事件是我们想要处理的 ename2handling[ename](); return true; else return false; end end); if ifTerminate then event.cancel(timer); -- 清理资源 os.exit(0); -- 退出 end end
2. 后台程序
在没有多任务操作系统的情况下编写在后台运行的程序是很麻烦、很原始的。您需要完全手动处理应用程序切入后台、恢复前台的所有逻辑,就如同在 DOS 中一样。在大部分时刻你不需要让多个程序同时在 opencomputers 上执行。因为 opencomputers 的主要目的是为工业控制以及自动化(即通常有一个固定的职责),而不是当作一个个人电脑来使用。
本代码没有经过实际测试,应该无法符合预期运作。本代码的作用仅仅是供您参考和学习操作系统原理,以及给予一个在OC中的bare bones的多任务的大致实现和思想。
local ifHide = false; -- 程序是否隐藏(后台运行) local outputBuffer = ""; -- 输出缓冲区 local timer = event.timer(1000, local function() -- 定时器 appPrint("timer!"); end); local pullInputThread = nil; -- 一个处理输入事件的“线程”——只执行一次的timer local redstoneEventHandler = event.listen("redstone_changed", local function(addr, side) appPrint("redstone! addr=", addr, "; side=", side); end); -- 监听将程序至于后台/前台的键盘事件 local hideShowKeyEventHandler = event.listen("key_up", local function(addr, char) -- 如果按下小键盘0,唤起应用 if char == keyboard.keys.numpad0 then show(); event.push("hide_all_programs"); -- 通知其他程序隐藏自己 -- 如果按下小键盘1,完全终止应用 elseif char == keyboard.keys.numpad1 then terminate(); end); -- 如果收到hide_all_programs信号,隐藏自己。 local hideAllProgramsEventHandler = event.listen("hide_all_programs", local function() hide(); end); -- 将程序至于后台 function hide() ifHide = true; event.cancel(pullInputThread); -- 强制终止正在执行的pullInput函数 os.exit(0); -- 直接退出 end -- 恢复程序于前台 function show() ifHide = false; dumpOutBuffer(); -- 将程序的输出dump到屏幕上 pullInputThread = event.timer(0, pullInput, 1); -- 执行pullInput“线程” end -- 完全终止程序 function terminate() event.cancel(timer); -- 注销定时器 event.ignore(redstoneEventHandler); -- 注销红石事件回调 event.ignore(hideShowKeyEventHandler); -- 注销将程序至于后台/前台的回调 event.ignore(hideAllProgramsEventHandler); -- 注销hide_all_programs信号的回调 end -- 打印 function appPrint(str) outputBuffer += str + "\n"; if not ifHide then print(str); end end -- 在屏幕上显示输出buffer function dumpOutBuffer() print(outputBuffer); end -- 处理键鼠事件 function pullInput() while true do if not ifHide then -- 仅仅在程序不在后台时方处理键鼠事件 local id, _, x, y = event.pullMultiple("touch", "interrupted"); -- 中断事件 if id == "interrupted" then appPrint("soft interrupt! hidding..."); hide(); elseif id == "touch" then appPrint("user touched! x=", arg["x"], "; y=", arg["y"]); end end end end -- main show();