工具特点
五按键独立控制:同时控制5个按键,每个按键独立设置内容和间隔
真后台发送:窗口最小化也能发送(ControlSend/PostMessage模式)
三重发送模式:
ControlSend:后台发送(推荐)
PostMessage:底层消息防检测
SendInput:前台模拟
智能窗口绑定:一键锁定目标窗口
实时状态监控:显示每个线程运行状态
完全开源:代码透明无后门
作者:Mr Bean(多年吾爱老坛友)
开发工具:AutoHotkey v2.0
运行平台:Windows 7/10/11
各位坛友大家好!
在吾爱论坛潜水多年,最近在魔兽乌龟服摸鱼时用AHK写了这个后台按键工具,压缩包大小仅2M,
特点就是给指定窗口连续发送后台按键,不干扰咱们前端牛马!现开源分享给大家!
重要提示:必须用管理员权限运行!否则后台发送会失效!
使用说明
第一步:右键以管理员身份运行脚本
第二步:点击【选择窗口】→ 切换到目标窗口 → 确定
第三步:设置按键内容和间隔(建议>100ms)
第四步:点击【启动】开始发送
---
高级功能
一键发送:独立线程,最多发送5个按键
保存配置:下次启动自动加载
紧急熔断:一键停止所有线程
---
下载与运行
成品版:下载附件压缩包→解压→右键管理员运行
源码版:安装AutoHotkey v2.0→保存代码为.ahk文件→右键管理员运行
---
下载点击上面的快捷目录即可跳转到下载地址
---
给坛友的话
> 第一次在吾爱发原创工具,心情激动又紧张
> 边学AHK边写的工具,源码带详细注释
> 郑重承诺:
100%原创无抄袭
无后门无病毒
永久开源免费
> 特别感谢:
吾爱论坛提供的学习平台!
>
热心坛友们的技术分享!
>
管理员大大们的辛苦付出!
>
遇到问题欢迎回帖交流!
觉得好用请给个免费评分鼓励~
完整开源源码
; ===== 多线程独立按键后台发送工具 (五按键版) ===== #SingleInstance Force #MaxThreadsPerHotkey 5 InstallKeybdHook() Persistent() ; 管理员权限检查 if !A_IsAdmin { try Run('*RunAs "' A_AhkPath '" "' A_ScriptFullPath '"') ExitApp } ; === 配置 === global Config := Map( "targetHwnd", 0, ; 目标窗口句柄 "targetTitle", "", ; 目标窗口标题 "targetClass", "", ; 目标窗口类名 "keyToSend1", "1", ; 按键1 "keyToSend2", "", ; 按键2 "keyToSend3", "", ; 按键3 "keyToSend4", "", ; 按键4 "keyToSend5", "", ; 按键5 "interval1", 500, ; 按键1发送间隔 "interval2", 1000, ; 按键2发送间隔 "interval3", 1500, ; 按键3发送间隔 "interval4", 2000, ; 按键4发送间隔 "interval5", 2500, ; 按键5发送间隔 "sendMethod", "ControlSend", ; 发送方法 "debug", true ; 启用调试模式 ) ; 按键线程状态 global KeyThreads := Map( "key1", Map("running", false, "timer", 0), "key2", Map("running", false, "timer", 0), "key3", Map("running", false, "timer", 0), "key4", Map("running", false, "timer", 0), "key5", Map("running", false, "timer", 0) ) ; === GUI 界面 - 优化版 === CreateGUI() { global ; 主窗口 MyGui := Gui("+Resize -MinimizeBox", "多线程后台按键发送工具 v5.0 by Mr Bean") MyGui.OnEvent("Close", GuiClose) MyGui.SetFont("s9", "Segoe UI") MyGui.MarginX := 10, MyGui.MarginY := 10 ; ===== 左侧区域:窗口设置 ===== leftSection := MyGui.Add("GroupBox", "x10 y10 w300 h150 Section", "目标窗口设置") ; 窗口选择行 MyGui.Add("Text", "xs+10 ys+30 w80", "窗口句柄:") hwndEdit := MyGui.Add("Edit", "vHwndEdit w100 xs+90 ys+25", Config["targetHwnd"]) selectBtn := MyGui.Add("Button", "x+5 yp-3 w90", "选择窗口") selectBtn.OnEvent("Click", SelectWindow) ; 窗口信息 (缩小输入框) MyGui.Add("Text", "xs+10 ys+65 w80", "窗口标题:") titleEdit := MyGui.Add("Edit", "vTitleEdit w200 xs+90 ys+60", Config["targetTitle"]) MyGui.Add("Text", "xs+10 ys+95 w80", "窗口类名:") classEdit := MyGui.Add("Edit", "vClassEdit w200 xs+90 ys+90", Config["targetClass"]) ; 发送方法 MyGui.Add("Text", "xs+10 ys+125 w80", "发送方法:") methodDDL := MyGui.Add("DropDownList", "vMethodDDL w120 xs+90 ys+122 Choose1", ["ControlSend", "PostMessage", "SendInput"]) methodDDL.Text := Config["sendMethod"] ; ===== 右侧区域:按键设置 ===== rightSection := MyGui.Add("GroupBox", "x320 y10 w300 h230 Section", "按键设置") ; 按键1设置 MyGui.Add("Text", "xs+10 ys+30 w40", "按键1:") keyEdit1 := MyGui.Add("Edit", "vKeyEdit1 w40 xs+50 ys+25", Config["keyToSend1"]) MyGui.Add("Text", "xs+100 ys+30 w50", "间隔(ms):") ; 宽度增加避免换行 intervalEdit1 := MyGui.Add("Edit", "vIntervalEdit1 w50 xs+150 ys+25", Config["interval1"]) key1ToggleBtn := MyGui.Add("Button", "x+10 yp-3 w80", "启动按键1") key1ToggleBtn.OnEvent("Click", (*) => ToggleKeyThread("key1")) ; 按键2设置 MyGui.Add("Text", "xs+10 ys+70 w40", "按键2:") keyEdit2 := MyGui.Add("Edit", "vKeyEdit2 w40 xs+50 ys+65", Config["keyToSend2"]) MyGui.Add("Text", "xs+100 ys+70 w50", "间隔(ms):") intervalEdit2 := MyGui.Add("Edit", "vIntervalEdit2 w50 xs+150 ys+65", Config["interval2"]) key2ToggleBtn := MyGui.Add("Button", "x+10 yp-3 w80", "启动按键2") key2ToggleBtn.OnEvent("Click", (*) => ToggleKeyThread("key2")) ; 按键3设置 MyGui.Add("Text", "xs+10 ys+110 w40", "按键3:") keyEdit3 := MyGui.Add("Edit", "vKeyEdit3 w40 xs+50 ys+105", Config["keyToSend3"]) MyGui.Add("Text", "xs+100 ys+110 w50", "间隔(ms):") intervalEdit3 := MyGui.Add("Edit", "vIntervalEdit3 w50 xs+150 ys+105", Config["interval3"]) key3ToggleBtn := MyGui.Add("Button", "x+10 yp-3 w80", "启动按键3") key3ToggleBtn.OnEvent("Click", (*) => ToggleKeyThread("key3")) ; 按键4设置 MyGui.Add("Text", "xs+10 ys+150 w40", "按键4:") keyEdit4 := MyGui.Add("Edit", "vKeyEdit4 w40 xs+50 ys+145", Config["keyToSend4"]) MyGui.Add("Text", "xs+100 ys+150 w50", "间隔(ms):") intervalEdit4 := MyGui.Add("Edit", "vIntervalEdit4 w50 xs+150 ys+145", Config["interval4"]) key4ToggleBtn := MyGui.Add("Button", "x+10 yp-3 w80", "启动按键4") key4ToggleBtn.OnEvent("Click", (*) => ToggleKeyThread("key4")) ; 按键5设置 (独立一行,位置下移) MyGui.Add("Text", "xs+10 ys+190 w40", "按键5:") keyEdit5 := MyGui.Add("Edit", "vKeyEdit5 w40 xs+50 ys+185", Config["keyToSend5"]) MyGui.Add("Text", "xs+100 ys+190 w50", "间隔(ms):") intervalEdit5 := MyGui.Add("Edit", "vIntervalEdit5 w50 xs+150 ys+185", Config["interval5"]) key5ToggleBtn := MyGui.Add("Button", "x+10 yp-3 w80", "启动按键5") key5ToggleBtn.OnEvent("Click", (*) => ToggleKeyThread("key5")) ; ===== 底部区域:控制按钮 ===== btnSection := MyGui.Add("GroupBox", "x10 y250 w610 h80 Section", "控制面板") ; 按钮行 sendBtn := MyGui.Add("Button", "xs+10 ys+25 w90 h30", "发送一次") sendBtn.SetFont("s10") sendBtn.OnEvent("Click", SendKeyOnce) saveBtn := MyGui.Add("Button", "x+20 yp w90 h30", "保存配置") saveBtn.SetFont("s10") saveBtn.OnEvent("Click", SaveConfig) stopAllBtn := MyGui.Add("Button", "x+20 yp w100 h30", "全部停止") stopAllBtn.SetFont("s10") stopAllBtn.OnEvent("Click", StopAllThreads) ; 状态指示器 (多行显示所有线程状态) statusGroup := MyGui.Add("GroupBox", "x10 y340 w610 h100", "线程状态") statusText := MyGui.Add("Text", "x20 y360 w590 h80", "就绪 - 请选择目标窗口") ; 显示GUI MyGui.Show("w630 h450") ; 保存控件引用 global GuiControls := Map( "hwndEdit", hwndEdit, "titleEdit", titleEdit, "classEdit", classEdit, "keyEdit1", keyEdit1, "keyEdit2", keyEdit2, "keyEdit3", keyEdit3, "keyEdit4", keyEdit4, "keyEdit5", keyEdit5, "intervalEdit1", intervalEdit1, "intervalEdit2", intervalEdit2, "intervalEdit3", intervalEdit3, "intervalEdit4", intervalEdit4, "intervalEdit5", intervalEdit5, "methodDDL", methodDDL, "statusText", statusText, "key1ToggleBtn", key1ToggleBtn, "key2ToggleBtn", key2ToggleBtn, "key3ToggleBtn", key3ToggleBtn, "key4ToggleBtn", key4ToggleBtn, "key5ToggleBtn", key5ToggleBtn ) } ; === 窗口选择功能 === SelectWindow(*) { global Config, GuiControls MsgBox("请切换到目标窗口,然后点击确定", "选择窗口", "Iconi T5") try { Config["targetHwnd"] := WinGetID("A") Config["targetTitle"] := WinGetTitle("A") Config["targetClass"] := WinGetClass("A") GuiControls["hwndEdit"].Value := Config["targetHwnd"] GuiControls["titleEdit"].Value := Config["targetTitle"] GuiControls["classEdit"].Value := Config["targetClass"] UpdateStatus("窗口已选择: " Config["targetTitle"]) } catch { UpdateStatus("错误: 无法获取窗口信息") } } ; === 发送功能 === SendKeyOnce(*) { global Config, GuiControls ; 从GUI获取当前设置 UpdateConfigFromGUI() ; 发送按键序列 if (Config["keyToSend1"] != "") SendKeyToWindow(Config["keyToSend1"]) if (Config["keyToSend2"] != "") SendKeyToWindow(Config["keyToSend2"]) if (Config["keyToSend3"] != "") SendKeyToWindow(Config["keyToSend3"]) if (Config["keyToSend4"] != "") SendKeyToWindow(Config["keyToSend4"]) if (Config["keyToSend5"] != "") SendKeyToWindow(Config["keyToSend5"]) UpdateStatus("按键序列发送完成!") } ; === 按键线程控制 === ToggleKeyThread(keyName) { global KeyThreads, Config, GuiControls ; 更新配置 UpdateConfigFromGUI() ; 获取按钮引用 btnRef := GuiControls[keyName . "ToggleBtn"] ; 获取线程状态 threadState := KeyThreads[keyName] if (threadState["running"]) { ; 停止线程 if (threadState["timer"] != 0 && IsObject(threadState["timer"])) { SetTimer(threadState["timer"], 0) threadState["timer"] := 0 } threadState["running"] := false btnRef.Text := "启动" . SubStr(keyName, 4) UpdateStatus() } else { ; 启动线程 threadState["running"] := true btnRef.Text := "停止" . SubStr(keyName, 4) ; 获取间隔时间 keyNum := SubStr(keyName, 4) interval := Config["interval" . keyNum] ; 创建线程 threadState["timer"] := SetTimer((*) => KeyThreadFunction(keyName), interval) UpdateStatus() } } ; 按键线程函数 KeyThreadFunction(keyName) { global Config, KeyThreads threadState := KeyThreads[keyName] if (!threadState["running"]) return keyNum := SubStr(keyName, 4) key := Config["keyToSend" . keyNum] if (key != "") { SendKeyToWindow(key) } } ; 停止所有线程 StopAllThreads(*) { global KeyThreads, GuiControls for keyName, threadState in KeyThreads { if (threadState["running"]) { if (threadState["timer"] != 0 && IsObject(threadState["timer"])) { SetTimer(threadState["timer"], 0) threadState["timer"] := 0 } threadState["running"] := false ; 更新按钮文本 btnRef := GuiControls[keyName . "ToggleBtn"] btnRef.Text := "启动" . SubStr(keyName, 4) } } UpdateStatus() } ; === 发送按键功能 === SendKeyToWindow(key) { global Config if (!Config["targetHwnd"] || !WinExist("ahk_id " Config["targetHwnd"])) { UpdateStatus("错误: 目标窗口不存在!") return false } try { switch (Config["sendMethod"]) { case "ControlSend": ControlSend key, , "ahk_id " Config["targetHwnd"] LogAction("ControlSend: " key " to " Config["targetTitle"]) return true case "PostMessage": vk := GetKeyVK(key) if (vk) { PostMessage(0x100, vk, 0, , "ahk_id " Config["targetHwnd"]) ; WM_KEYDOWN PostMessage(0x101, vk, 0xC0000001, , "ahk_id " Config["targetHwnd"]) ; WM_KEYUP LogAction("PostMessage: " key " to " Config["targetTitle"]) return true } return false case "SendInput": WinActivate "ahk_id " Config["targetHwnd"] WinWaitActive("ahk_id " Config["targetHwnd"], , 0.5) Send key LogAction("SendInput: " key " to " Config["targetTitle"]) return true } } catch as e { LogAction("错误: " e.Message) return false } } ; 获取按键虚拟键码 GetKeyVK(key) { static map := Map( "1", 0x31, "2", 0x32, "3", 0x33, "4", 0x34, "5", 0x35, "f", 0x46, "e", 0x45, "g", 0x47, "q", 0x51, "v", 0x56, "x", 0x58, "z", 0x5A, "c", 0x43, "r", 0x52, "t", 0x54, "h", 0x48, "a", 0x41, "s", 0x53, "d", 0x44, "w", 0x57, "Space", 0x20, "Enter", 0x0D, "Tab", 0x09, "Esc", 0x1B, "Backspace", 0x08, "Up", 0x26, "Down", 0x28, "Left", 0x25, "Right", 0x27, "F1", 0x70, "F2", 0x71, "F3", 0x72, "F4", 0x73, "F5", 0x74, "F6", 0x75, "F7", 0x76, "F8", 0x77, "F9", 0x78, "F10", 0x79, "Ctrl+C", "CtrlC", "Ctrl+V", "CtrlV", "Alt+Tab", "AltTab" ) return map.Get(key, 0) } ; === 配置管理 === UpdateConfigFromGUI() { global Config, GuiControls ; 保存当前配置 Config["targetHwnd"] := GuiControls["hwndEdit"].Value Config["targetTitle"] := GuiControls["titleEdit"].Value Config["targetClass"] := GuiControls["classEdit"].Value Config["keyToSend1"] := GuiControls["keyEdit1"].Value Config["keyToSend2"] := GuiControls["keyEdit2"].Value Config["keyToSend3"] := GuiControls["keyEdit3"].Value Config["keyToSend4"] := GuiControls["keyEdit4"].Value Config["keyToSend5"] := GuiControls["keyEdit5"].Value Config["sendMethod"] := GuiControls["methodDDL"].Text ; 处理按键间隔 Config["interval1"] := ValidateInterval(GuiControls["intervalEdit1"].Value, 1) Config["interval2"] := ValidateInterval(GuiControls["intervalEdit2"].Value, 2) Config["interval3"] := ValidateInterval(GuiControls["intervalEdit3"].Value, 3) Config["interval4"] := ValidateInterval(GuiControls["intervalEdit4"].Value, 4) Config["interval5"] := ValidateInterval(GuiControls["intervalEdit5"].Value, 5) } ; 验证间隔时间 ValidateInterval(value, keyNum) { try { interval := Integer(value) if (interval >= 50 && interval <= 5000) { return interval } } catch { ; 捕获转换错误 } ; 无效值重置为默认 defaultIntervals := [500, 1000, 1500, 2000, 2500] defaultInterval := defaultIntervals[keyNum-1] GuiControls["intervalEdit" . keyNum].Value := defaultInterval UpdateStatus("警告: 按键" keyNum "间隔无效,已重置为" defaultInterval "ms") return defaultInterval } SaveConfig(*) { global Config, GuiControls ; 更新配置 UpdateConfigFromGUI() ; 保存到INI文件 IniWrite(Config["targetHwnd"], "SendKeys.ini", "Config", "targetHwnd") IniWrite(Config["targetTitle"], "SendKeys.ini", "Config", "targetTitle") IniWrite(Config["targetClass"], "SendKeys.ini", "Config", "targetClass") IniWrite(Config["keyToSend1"], "SendKeys.ini", "Config", "keyToSend1") IniWrite(Config["keyToSend2"], "SendKeys.ini", "Config", "keyToSend2") IniWrite(Config["keyToSend3"], "SendKeys.ini", "Config", "keyToSend3") IniWrite(Config["keyToSend4"], "SendKeys.ini", "Config", "keyToSend4") IniWrite(Config["keyToSend5"], "SendKeys.ini", "Config", "keyToSend5") IniWrite(Config["interval1"], "SendKeys.ini", "Config", "interval1") IniWrite(Config["interval2"], "SendKeys.ini", "Config", "interval2") IniWrite(Config["interval3"], "SendKeys.ini", "Config", "interval3") IniWrite(Config["interval4"], "SendKeys.ini", "Config", "interval4") IniWrite(Config["interval5"], "SendKeys.ini", "Config", "interval5") IniWrite(Config["sendMethod"], "SendKeys.ini", "Config", "sendMethod") UpdateStatus("配置已保存!") } LoadConfig() { global Config ; 从INI文件加载 if (FileExist("SendKeys.ini")) { Config["targetHwnd"] := IniRead("SendKeys.ini", "Config", "targetHwnd", 0) Config["targetTitle"] := IniRead("SendKeys.ini", "Config", "targetTitle", "") Config["targetClass"] := IniRead("SendKeys.ini", "Config", "targetClass", "") Config["keyToSend1"] := IniRead("SendKeys.ini", "Config", "keyToSend1", "1") Config["keyToSend2"] := IniRead("SendKeys.ini", "Config", "keyToSend2", "") Config["keyToSend3"] := IniRead("SendKeys.ini", "Config", "keyToSend3", "") Config["keyToSend4"] := IniRead("SendKeys.ini", "Config", "keyToSend4", "") Config["keyToSend5"] := IniRead("SendKeys.ini", "Config", "keyToSend5", "") Config["interval1"] := IniRead("SendKeys.ini", "Config", "interval1", 500) Config["interval2"] := IniRead("SendKeys.ini", "Config", "interval2", 1000) Config["interval3"] := IniRead("SendKeys.ini", "Config", "interval3", 1500) Config["interval4"] := IniRead("SendKeys.ini", "Config", "interval4", 2000) Config["interval5"] := IniRead("SendKeys.ini", "Config", "interval5", 2500) Config["sendMethod"] := IniRead("SendKeys.ini", "Config", "sendMethod", "ControlSend") } } ; === 实用函数 === UpdateStatus(message := "") { global GuiControls, KeyThreads, Config if (message != "") { GuiControls["statusText"].Value := message return } ; 构建多线程状态信息 status := "" status .= "按键1: " (KeyThreads["key1"]["running"] ? "运行中 (" Config["interval1"] "ms)" : "停止") "`n" status .= "按键2: " (KeyThreads["key2"]["running"] ? "运行中 (" Config["interval2"] "ms)" : "停止") "`n" status .= "按键3: " (KeyThreads["key3"]["running"] ? "运行中 (" Config["interval3"] "ms)" : "停止") "`n" status .= "按键4: " (KeyThreads["key4"]["running"] ? "运行中 (" Config["interval4"] "ms)" : "停止") "`n" status .= "按键5: " (KeyThreads["key5"]["running"] ? "运行中 (" Config["interval5"] "ms)" : "停止") GuiControls["statusText"].Value := status } LogAction(message) { global Config if (Config["debug"]) { FileAppend FormatTime(, "yyyy-MM-dd HH:mm:ss") " - " message "`n", "SendKeys.log" } } GuiClose(*) { ; 停止所有线程 StopAllThreads() Sleep 100 ExitApp } ; === 启动 === LoadConfig() CreateGUI()
下载地址
https://pan.baidu.com/s/1uCLC64C7Nm1PQ18JRS-nWg?pwd=mc63 提取码: mc63
https://pan.quark.cn/s/43661ec4217d
转载自
https://www.52pojie.cn/thread-2039403-1-1.html
评论抢沙发