好友
阅读权限10
听众
最后登录1970-1-1
|
本帖最后由 alomoi 于 2026-1-27 14:14 编辑
用你的手机当遥控器,对电脑进行一些简单“遥控”
支持自定义命令,可以添加你自己的程序到“遥控”菜单,一键启动
程序首次运行会弹出日志窗口,提示web服务运行的端口(后续可以自行修改)及默认用户名密码
日志界面仅在首次运行时弹出,后续可通过程序托盘图标右键,选择“系统日志”进入
通过程序托盘图标右键,选择“自定义命令”可自行添加需要“遥控”启动的程序
注意:如果你添加的程序包括参数和配置文件,需为配置文件填写完整路径(如fprc示例)
在浏览器中通过IP+端口可访问web控制台页面,登录之后可看到常驻命令和添加的自定义命令,点击对应的按钮即可执行
点击下方的“系统设置”可修改用户名、密码及服务运行端口
程序使用aardio编写,编译之后的程序有误报情况
不放心的可通过以下源码自行编译
[AAuto] 纯文本查看 复制代码 import process.mutex;
var appId = "{A7B8C9D0-E1F2-4A5B-B6C7-D8E9F0A1B2C3}";
var mutex = process.mutex(appId);
if(mutex.conflict){
import winex;
var hwnd = winex.find( , "web控制台-日志");
if(hwnd){
win.showForeground(hwnd);
win.flash(hwnd, 1/*_FLASHW_CAPTION*/ | 4/*_FLASHW_TRAY*/);
}
return;
};
import win.ui.menu;
import win.util.tray;
import win.ui.grid;
import crypt;
import fsys.config;
import inet.url;
import gdip.snap;
import fsys.dlg;
import process;
import wsock.tcp.asyncHttpServer;
/*DSG{{*/
var winform = win.form(text="web控制台-日志";right=544;bottom=320;max=false)
winform.add(
edit={cls="edit";left=22;top=28;right=521;bottom=284;ah=1;aw=1;edge=1;multiline=1;z=1}
)
/*}}*/
var config = fsys.config("/config/");
if(!config.auth.user){
initialization = true
config.auth.user = "admin";
config.auth.pwdHash = crypt.sha256("123456");
config.commands.calc = { cmd = "calc.exe"; title = "打开计算器" };
config.commands.notepad = { cmd = "notepad.exe"; title = "打开记事本" };
config.saveAll();
}
var showCommandEditor = function(){
/*DSG{{*/
var frmChild = win.form(text="web控制台-自定义命令";right=565;bottom=385;parent=winform)
frmChild.add(
btnAdd={cls="button";text="新增命令";left=332;top=316;right=431;bottom=360;ah=1;aw=1;z=2};
btnDel={cls="button";text="删除选中";left=450;top=316;right=549;bottom=360;ah=1;aw=1;z=3};
listview={cls="listview";left=15;top=15;right=551;bottom=297;ah=1;aw=1;edge=1;fullRow=1;z=1}
)
/*}}*/
var grid = win.ui.grid(frmChild.listview);
grid.columns = {
{"路径键名 (URL)"; 120};
{"显示标题"; 120};
{"执行程序/路径"; -1}
}
var reloadData = function(){
grid.clear();
for(name, cfg in config.commands){
if( type(cfg) == type.table ){
grid.addItem({ name; cfg.title; cfg.cmd });
}
}
}
reloadData();
frmChild.btnAdd.oncommand = function(id,event){
var path = fsys.dlg.open("所有文件|*.*||", "选择要执行的程序");
if(path){
var name = io.splitpath(path).name;
var key = name;
var i = 1;
while(config.commands[key]){
key = name + i;
i++;
}
config.commands[key] = { cmd = path; title = name };
config.saveAll();
reloadData();
}
}
frmChild.btnDel.oncommand = function(id,event){
var selIdx = frmChild.listview.selIndex;
if(!selIdx) return frmChild.msgbox("请先选择要删除的项");
var key = frmChild.listview.getItemText(selIdx, 1);
if(frmChild.msgboxTest("确定要删除命令 ["+key+"] 吗?")){
config.commands[key] = null;
config.saveAll();
reloadData();
}
}
grid.onEditChanged = function(text, row, col){
var key = frmChild.listview.getItemText(row, 1);
var cfg = config.commands[key];
if(col == 1){
if(#text && text != key){
config.commands[text] = cfg;
config.commands[key] = null;
}
}
elseif(col == 2){
cfg.title = text;
}
elseif(col == 3){
cfg.cmd = text;
}
config.saveAll();
return true;
}
frmChild.show();
}
var server = wsock.tcp.asyncHttpServer();
var tray = win.util.tray(winform)
tray.tip = "web控制台-服务端"
winform.onTrayMessage = {
[0x205 /*_WM_RBUTTONUP*/ ] = function(id){
var popmenu = win.ui.popmenu(winform);
popmenu.add("系统日志", function(id){
winform.show();
win.setForeground(winform.hwnd);
win.show(winform.hwnd, 0x9/*_SW_RESTORE*/);
});
popmenu.add("自定义命令", function(id){
showCommandEditor();
});
popmenu.add();
popmenu.add("访问web控制台", function(id){
raw.execute(server.getUrl());
});
popmenu.add();
popmenu.add("🔗吾爱破解论坛", function(id){
process.execute("https://www.52pojie.cn/");
});
popmenu.add("退出程序", function(id){
winform.close();
win.quitMessage();
});
popmenu.popup();
};
[0x203 /*_WM_LBUTTONDBLCLK*/] = function(id){ winform.show(); };
}
winform.onClose = function(){ winform.show(false); return false; }
server.run(
function(response, request){
var msgPage = function(title, msg, isError){
var actionUrl = isError ? "javascript:history.back();" : "/";
var actionText = isError ? "返回重试" : "返回首页";
return `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body{ font-family:sans-serif; display:flex; justify-content:center; align-items:center; height:100vh; margin:0; background:#f0f2f5;}
.card{ background:white; padding:30px; border-radius:8px; box-shadow:0 2px 10px rgba(0,0,0,0.1); width:90%; max-width:300px; text-align:center;}
.icon{ font-size:48px; margin-bottom:10px; color:` + (isError ? "#e74c3c" : "#2ecc71") + `;}
h2{ margin:10px 0; color:#333;} p{ color:#666; margin-bottom:20px;}
.btn{ display:inline-block; text-decoration:none; background:#0078d4; color:white; padding:10px 20px; border-radius:4px; font-size:16px; border:none; cursor:pointer;}
.timer{ font-size:12px; color:#999; margin-top:15px;}
</style></head>
<body>
<div class="card">
<div class="icon">` + (isError ? "✕" : "✓") + `</div>
<h2>` + title + `</h2>
<p>` + msg + `</p>
<a href="` + actionUrl + `" class="btn" id="btnAction">` + actionText + ` (5)</a>
<div class="timer">页面将在 5 秒后自动跳转</div>
</div>
<script>
(function(){
var wait = 5;
var btn = document.getElementById('btnAction');
var actionName = "` + actionText + `";
var url = "` + actionUrl + `";
var timer = setInterval(function(){
wait--;
if(wait > 0){
btn.innerText = actionName + " (" + wait + ")";
} else {
clearInterval(timer);
if(url.indexOf('javascript:') === 0){
history.back();
} else {
location.href = url;
}
}
}, 1000);
})();
</script>
</body></html>`;
}
var confirmPage = function(title, msg, actionPath, btnText) {
return `
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body{ font-family:sans-serif; display:flex; justify-content:center; align-items:center; height:100vh; margin:0; background:#f0f2f5;}
.card{ background:white; padding:30px; border-radius:8px; box-shadow:0 2px 10px rgba(0,0,0,0.1); width:90%; max-width:300px; text-align:center;}
.icon{ font-size:48px; margin-bottom:10px; color:#f39c12;}
h2{ margin:10px 0; color:#333;} p{ color:#666; margin-bottom:20px;}
.btn-danger{ display:inline-block; text-decoration:none; background:#e74c3c; color:white; padding:10px 20px; border-radius:4px; font-size:16px; border:none; cursor:pointer;}
.btn-cancel{ display:inline-block; text-decoration:none; background:#95a5a6; color:white; padding:10px 20px; border-radius:4px; font-size:16px; border:none; cursor:pointer; margin-left:10px;}
</style></head>
<body>
<div class="card">
<div class="icon">⚠</div>
<h2>` + title + `</h2>
<p>` + msg + `</p>
<a href="` + actionPath + `?confirm=1" class="btn-danger">` + btnText + `</a>
<a href="/" class="btn-cancel">取消</a>
</div>
</body></html>`;
}
if (request.path == "/login"){
if(request.method == "POST"){
var user = request.post["user"];
var pwd = request.post["pwd"];
if(user == config.auth.user && crypt.sha256(pwd) == config.auth.pwdHash){
winform.edit.print(tostring(time()), request.remoteAddr, user,"登录成功");
session.loggedIn = true;
response.redirect("/");
return;
}
winform.edit.print(tostring(time()), request.remoteAddr, user,"登录失败");
response.write(msgPage("登录失败", "用户名或密码错误!", true));
return;
}
response.write(`
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body{ font-family:sans-serif; display:flex; justify-content:center; align-items:center; min-height:100vh; margin:0; background:#f0f2f5;}
.container{ background:white; padding:30px; border-radius:8px; box-shadow:0 2px 10px rgba(0,0,0,0.1); width:90%; max-width:320px;}
h2{ text-align:center; color:#333; margin-top:0;}
label{ display:block; margin-bottom:5px; color:#666; font-size:14px;}
input{ width:100%; padding:12px; margin-bottom:20px; border:1px solid #ddd; box-sizing:border-box; border-radius:4px; font-size:16px;}
button{ width:100%; padding:12px; background:#0078d4; color:white; border:none; border-radius:4px; cursor:pointer; font-size:16px; transition: background 0.3s;}
button:hover{ background:#005a9e; }
</style>
</head>
<body>
<div class="container">
<h2>Web控制台登录</h2>
<form method="post" action="/login">
<label>用户名</label>
<input name="user" type="text" placeholder="请输入用户名" required>
<label>密码</label>
<input name="pwd" type="password" placeholder="请输入密码" required>
<button type="submit">登录</button>
</form>
</div>
</body></html>
`);
return;
}
if(!session.loggedIn){
response.redirect("/login");
return;
}
if(request.path != "/favicon.ico"){
if(request.path = "/main.aardio"){
winform.edit.print(tostring(time()), request.remoteAddr, request.method, "/");
}
else{
winform.edit.print(tostring(time()), request.remoteAddr, request.method, request.path);
}
}
if(request.path == "/logout"){
session.loggedIn = null;
response.redirect("/login");
return;
}
var cmdName = string.slice(request.path, 2);
if( !string.indexOf(cmdName,"/") ){
var cfgCmd = config.commands[cmdName];
if(cfgCmd && type(cfgCmd) == type.table){
process(cfgCmd.cmd);
winform.edit.print(tostring(time()), "执行自定义命令: " + (cfgCmd.title || cmdName));
response.write(msgPage("指令已发送", (cfgCmd.title || cmdName), false));
return;
}
}
select(request.path) {
case "/@settings" {
if (request.method == "POST") {
var newUser = request.post["newuser"];
var newPwd = request.post["newpwd"];
var portInput = request.post["newport"];
if( newUser && #newUser && newPwd && #newPwd ){
config.auth.user = newUser;
config.auth.pwdHash = crypt.sha256(newPwd);
if( !portInput || !#string.trim(portInput) ){
config.auth.port = 0;
}
else {
var p = tonumber(portInput);
if(p !== null && p >= 0 && p <= 65535){
config.auth.port = p;
}
}
config.auth.save();
winform.edit.print(tostring(time()), request.remoteAddr, newUser,"已修改配置");
response.write(msgPage("修改成功", "配置已更新。若修改了端口,请手动重启程序生效。", false));
return;
}
response.write(msgPage("修改失败", "用户名或密码不能为空。", true));
return;
}
response.write(`
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body{ font-family:sans-serif; display:flex; justify-content:center; align-items:center; min-height:100vh; margin:0; background:#f0f2f5;}
.container{ background:white; padding:30px; border-radius:8px; box-shadow:0 2px 10px rgba(0,0,0,0.1); width:90%; max-width:320px;}
h2{ text-align:center; color:#333; margin-top:0;}
label{ display:block; margin-bottom:5px; color:#666; font-size:14px;}
.hint{ font-size:12px; color:#999; margin-bottom:15px; display:block; margin-top:-15px;}
input{ width:100%; padding:12px; margin-bottom:20px; border:1px solid #ddd; box-sizing:border-box; border-radius:4px; font-size:16px;}
button{ width:100%; padding:12px; background:#0078d4; color:white; border:none; border-radius:4px; cursor:pointer; font-size:16px; transition: background 0.3s;}
button:hover{ background:#005a9e; }
.footer-links{ text-align:center; margin-top:20px;}
.footer-links a{ color:#666; text-decoration:none; font-size:14px;}
.footer-links a:hover{ text-decoration:underline;}
</style>
</head>
<body>
<div class="container">
<h2>系统设置</h2>
<form method="post" action="/@settings">
<label>用户名</label>
<input name="newuser" type="text" value="` + (config.auth.user || "") + `" required>
<label>新密码</label>
<input name="newpwd" type="password" placeholder="填写新密码" required>
<label>服务端口</label>
<input name="newport" type="number" value="` + (config.auth.port : "") + `" placeholder="留空则使用随机端口" min="0" max="65535">
<span class="hint">范围: 1-65535。留空或设为 0 则由系统随机分配。</span>
<button type="submit">保存修改</button>
</form>
<div class="footer-links">
<a href="/">← 返回首页</a>
</div>
</div>
</body></html>
`);
return;
}
case "/@printscreen" {
var bmp = gdip.snap();
if(bmp){
var buf = bmp.saveToBuffer("*.jpg", 80);
bmp.dispose();
if(buf){
response.contentType = "image/jpeg";
response.write(buf);
return;
}
}
response.errorStatus(500, "截图失败");
}
case "/@lockpc" {
::User32.LockWorkStation();
response.write(msgPage("指令已发送", ("锁定屏幕"), false));
return;
}
case "/@reboot" {
if (request.query("confirm") == "1") {
winform.edit.print(tostring(time()), request.remoteAddr, user,"确认执行重启指令");
raw.execute("shutdown.exe", "-r -f -t 0", "", 0/*_SW_HIDE*/);
response.write(msgPage("指令已发送", "计算机正在重启...", false));
return;
}
response.write(confirmPage("确认重启", "您确定要重启这台计算机吗?未保存的工作将会丢失。", "/@reboot", "确认重启"));
return;
}
case "/@poweroff" {
if (request.query("confirm") == "1") {
winform.edit.print(tostring(time()), request.remoteAddr, user,"确认执行关机指令");
raw.execute("shutdown.exe", "-s -f -t 0", "", 0/*_SW_HIDE*/);
response.write(msgPage("指令已发送", "计算机正在关机...", false));
return;
}
response.write(confirmPage("确认关机", "您确定要关闭这台计算机吗?未保存的工作将会丢失。", "/@poweroff", "确认关机"));
return;
}
}
var dynamicButtons = "";
for(name, cfg in config.commands){
if( type(cfg) == "table" && !string.startsWith(name,"_") && name != "save" ){
var title = cfg.title || name;
dynamicButtons += `<a href="/` + name + `" class="btn">` + title + `</a>`;
}
}
response.write(`
<!DOCTYPE html>
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>
body { display:flex; flex-direction:column; align-items:center; padding:20px; background:#f5f5f5; font-family:sans-serif;}
.btn { display:block; margin:10px 0; padding:15px; background:#0078d4; color:white; text-decoration:none; text-align:center; width:90%; max-width:300px; border-radius:8px; font-size:18px;}
.btn-sys { display:block; margin:10px 0; padding:15px; background:#50677a; color:white; text-decoration:none; text-align:center; width:90%; max-width:300px; border-radius:8px; font-size:18px;}
.logout { color:#666; margin-top:20px; font-size:14px; text-decoration:none;}
hr { width:100%; border:0; border-top:1px solid #ddd; margin:20px 0; }
</style></head><body>
<h3>Web控制台</h3>
<!-- 插入动态生成的按钮 -->
` + dynamicButtons + `
<a href="/@printscreen" target="_blank" class="btn-sys">屏幕截图</a>
<a href="/@lockpc" class="btn-sys">锁定屏幕</a>
<a href="/@reboot" class="btn-sys">重启电脑</a>
<a href="/@poweroff" class="btn-sys">关闭电脑</a>
<hr>
<a href="/@settings" class="logout">系统设置</a>
<a href="/logout" class="logout">退出登录</a>
</body></html>
`);
}
);
if (config.auth.port){
server.start("0.0.0.0", config.auth.port);
}
else{
server.start();
}
winform.edit.print(tostring(time()), "web控制台已启动: ", server.getUrl());
if (initialization = true){
winform.edit.print(tostring(time()), "程序初始化成功", "默认账号密码:admin/123456");
winform.show();win.setForeground(winform.hwnd);win.show(winform.hwnd, 0x9/*_SW_RESTORE*/);
}
win.loopMessage();
|
免费评分
-
查看全部评分
|