package main import ( "encoding/json" "fmt" "log" "net/http" "os/exec" "syscall" "time" "unsafe" ) type RequestData struct { Type string `json:"type"` Path string `json:"path"` FileName string `json:"fileName"` } // 常量 const ( VK_CONTROL = 0x11 VK_V = 0x56 ) var ( user32 = syscall.NewLazyDLL("user32.dll") findWindowW = user32.NewProc("FindWindowW") moveWindow = user32.NewProc("MoveWindow") setForegroundWindow = user32.NewProc("SetForegroundWindow") getWindowRect = user32.NewProc("GetWindowRect") setCursorPos = user32.NewProc("SetCursorPos") mouse_event = user32.NewProc("mouse_event") keybd_event = user32.NewProc("keybd_event") ) type RECT struct { Left int32 Top int32 Right int32 Bottom int32 } // 回车键的虚拟键码 const VK_RETURN = 0x0D const KEYEVENTF_KEYUP = 0x0002 // 简化函数 func FindWindow(title string) (uintptr, error) { titlePtr, err := syscall.UTF16PtrFromString(title) if err != nil { return 0, err } hwnd, _, err := findWindowW.Call(0, uintptr(unsafe.Pointer(titlePtr))) if hwnd == 0 { return 0, fmt.Errorf("窗口未找到: %v", err) } return hwnd, nil } func MoveWindow(hwnd uintptr, x, y, w, h int32) error { ret, _, err := moveWindow.Call(hwnd, uintptr(x), uintptr(y), uintptr(w), uintptr(h), 1) if ret == 0 { return fmt.Errorf("移动窗口失败: %v", err) } return nil } func SetForegroundWindow(hwnd uintptr) error { ret, _, err := setForegroundWindow.Call(hwnd) if ret == 0 { return fmt.Errorf("设置前台窗口失败: %v", err) } return nil } func GetWindowRect(hwnd uintptr) (RECT, error) { var rect RECT ret, _, err := getWindowRect.Call(hwnd, uintptr(unsafe.Pointer(&rect))) if ret == 0 { return rect, fmt.Errorf("获取窗口矩形失败: %v", err) } return rect, nil } func SetCursorPos(x, y int32) error { ret, _, err := setCursorPos.Call(uintptr(x), uintptr(y)) if ret == 0 { return fmt.Errorf("设置光标位置失败: %v", err) } return nil } func MouseClick(x, y int32) error { // 移动鼠标 if err := SetCursorPos(x, y); err != nil { return err } time.Sleep(100 * time.Millisecond) // 左键按下 (0x0002 = MOUSEEVENTF_LEFTDOWN) mouse_event.Call(2, 0, 0, 0, 0) time.Sleep(50 * time.Millisecond) // 左键释放 (0x0004 = MOUSEEVENTF_LEFTUP) mouse_event.Call(4, 0, 0, 0, 0) return nil } func Paste() { // Ctrl 按下 keybd_event.Call(uintptr(VK_CONTROL), 0, 0, 0) time.Sleep(50 * time.Millisecond) // V 按下 keybd_event.Call(uintptr(VK_V), 0, 0, 0) time.Sleep(50 * time.Millisecond) // V 释放 (0x0002 = KEYEVENTF_KEYUP) keybd_event.Call(uintptr(VK_V), 0, 2, 0) time.Sleep(50 * time.Millisecond) // Ctrl 释放 keybd_event.Call(uintptr(VK_CONTROL), 0, 2, 0) } func PressEnter() { // 按下回车键 keybd_event.Call( uintptr(VK_RETURN), // bVk 0, // bScan 0, // dwFlags (按下) 0, // dwExtraInfo ) time.Sleep(5 * time.Millisecond) // 释放回车键 keybd_event.Call( uintptr(VK_RETURN), // bVk 0, // bScan uintptr(KEYEVENTF_KEYUP), // dwFlags (释放) 0, // dwExtraInfo ) } // 使用系统命令设置剪贴板(更可靠) func SetClipboard(text string) error { // 方法1:使用 clip 命令 cmd := exec.Command("cmd", "/c", fmt.Sprintf("echo %s | clip", text)) if err := cmd.Run(); err == nil { return nil } // 方法2:使用 PowerShell cmd2 := exec.Command("powershell", "-Command", fmt.Sprintf("Set-Clipboard -Value '%s'", text)) return cmd2.Run() } func findAndOperateWindow(title string, filePath string, fileName string) { fmt.Printf("开始查找窗口: %s\n", title) var hwnd uintptr var err error found := false // 10秒内每秒尝试查找窗口 for i := 0; i < 10; i++ { fmt.Printf("尝试第 %d 次查找...\n", i+1) hwnd, err = FindWindow(title) if err == nil && hwnd != 0 { found = true fmt.Printf("找到窗口: %s (句柄: 0x%X)\n", title, hwnd) break } time.Sleep(1 * time.Second) } if !found { log.Printf("在10秒内未找到窗口: %s", title) log.Println("请确保:") log.Println("1. 窗口已经打开") log.Println("2. 窗口标题完全匹配: " + title) log.Println("3. 可能需要以管理员身份运行此程序") return } // 激活窗口 if err := SetForegroundWindow(hwnd); err != nil { log.Printf("激活窗口失败: %v", err) } time.Sleep(500 * time.Millisecond) // 调整窗口大小到800x600 fmt.Println("正在修改窗口大小为800x600...") if err := MoveWindow(hwnd, 100, 100, 800, 600); err != nil { log.Printf("调整窗口大小失败: %v", err) } else { fmt.Println("窗口大小修改成功") } // 获取窗口位置 rect, err := GetWindowRect(hwnd) if err != nil { log.Printf("获取窗口位置失败: %v", err) } else { fmt.Printf("窗口位置: X=%d, Y=%d\n", rect.Left, rect.Top) } // 等待窗口调整完成 time.Sleep(500 * time.Millisecond) MouseClick(rect.Left+450, rect.Top+60) SetClipboard(filePath) time.Sleep(500 * time.Millisecond) // 粘贴剪贴板内容 fmt.Println("正在粘贴剪贴板内容...") Paste() fmt.Println("粘贴完成") time.Sleep(500 * time.Millisecond) fmt.Println("按回车键") PressEnter() fmt.Println("操作完成") MouseClick(rect.Left+450, rect.Top+530) time.Sleep(2 * time.Second) SetClipboard(fileName) time.Sleep(500 * time.Millisecond) Paste() time.Sleep(500 * time.Millisecond) PressEnter() } func handlePostRequest(w http.ResponseWriter, r *http.Request) { // 只处理POST请求 if r.Method != http.MethodPost { http.Error(w, "只支持POST请求", http.StatusMethodNotAllowed) return } // 解析JSON数据 var data RequestData decoder := json.NewDecoder(r.Body) if err := decoder.Decode(&data); err != nil { http.Error(w, "JSON解析错误: "+err.Error(), http.StatusBadRequest) return } defer r.Body.Close() // 输出接收到的数据 fmt.Println("=== 接收到POST请求数据 ===") fmt.Printf("类型 (type): %s\n", data.Type) fmt.Printf("路径 (path): %s\n", data.Path) fmt.Printf("文件名 (fileName): %s\n", data.FileName) fmt.Println("==========================") // 根据type执行不同操作 if data.Type == "openFile" { // 在新goroutine中执行窗口操作,避免阻塞HTTP响应 go func() { findAndOperateWindow("打开", data.Path, data.FileName) }() // 返回响应 w.Header().Set("Content-Type", "application/json") response := map[string]interface{}{ "status": "processing", "message": "正在执行窗口操作", "data": data, } json.NewEncoder(w).Encode(response) return } // 返回成功响应 w.Header().Set("Content-Type", "application/json") response := map[string]interface{}{ "status": "success", "message": "数据接收成功", "data": data, } json.NewEncoder(w).Encode(response) } func main() { fmt.Println("窗口操作服务启动...") fmt.Println("注意:某些窗口操作可能需要管理员权限") fmt.Println("如果需要,请以管理员身份运行此程序") fmt.Println() // 设置处理POST请求的路由 http.HandleFunc("/", handlePostRequest) // 设置服务器监听8866端口 port := ":8866" fmt.Printf("服务器正在监听端口 %s ...\n", port) fmt.Println("等待POST请求...") fmt.Println() // 启动HTTP服务器 if err := http.ListenAndServe(port, nil); err != nil { log.Fatal("服务器启动失败:", err) } } // 前端JS请求示例 // const myHeaders = new Headers(); // myHeaders.append("Content-Type", "application/json"); // const raw = JSON.stringify({ // "type": "openFile", // "path": "C:\\Users\\mail\\Downloads", // "fileName": "128.png" // }); // const requestOptions = { // method: "POST", // headers: myHeaders, // body: raw, // }; // fetch("http://127.0.0.1:8866/", requestOptions) // .then((response) => response.text()) // .then((result) => console.log(result)) // .catch((error) => console.error(error));