mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-08 14:34:13 +08:00
280 lines
10 KiB
C#
280 lines
10 KiB
C#
using System;
|
||
using System.IO;
|
||
using System.Text;
|
||
using System.Threading;
|
||
using System.Windows.Forms;
|
||
using System.Runtime.InteropServices;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Drawing;
|
||
|
||
class Monitor {
|
||
// Win32 API
|
||
[DllImport("user32.dll", SetLastError = true)]
|
||
private static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
|
||
|
||
[DllImport("user32.dll", SetLastError = true)]
|
||
private static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
|
||
|
||
private static FileSystemWatcher fsWatcher;
|
||
private static IntPtr nextClipboardViewer;
|
||
private static ClipboardForm clipboardForm;
|
||
private static bool running = true;
|
||
private static bool listenOnce = false;
|
||
private static bool isFirstClipboardEvent = true;
|
||
|
||
private class ClipboardForm : Form {
|
||
public ClipboardForm() {
|
||
this.ShowInTaskbar = false;
|
||
this.Visible = false;
|
||
this.WindowState = FormWindowState.Minimized;
|
||
this.FormBorderStyle = FormBorderStyle.None;
|
||
this.Size = new System.Drawing.Size(1, 1);
|
||
this.Load += (sender, e) => {
|
||
nextClipboardViewer = SetClipboardViewer(this.Handle);
|
||
};
|
||
this.FormClosing += (sender, e) => {
|
||
ChangeClipboardChain(this.Handle, nextClipboardViewer);
|
||
};
|
||
}
|
||
|
||
protected override CreateParams CreateParams {
|
||
get {
|
||
CreateParams cp = base.CreateParams;
|
||
cp.ExStyle |= 0x80; // WS_EX_TOOLWINDOW
|
||
return cp;
|
||
}
|
||
}
|
||
|
||
protected override void WndProc(ref Message m) {
|
||
if (m.Msg == 0x308) { // WM_DRAWCLIPBOARD
|
||
if (isFirstClipboardEvent) {
|
||
isFirstClipboardEvent = false;
|
||
} else {
|
||
HandleClipboardChanged();
|
||
if (listenOnce) {
|
||
running = false;
|
||
this.BeginInvoke(new Action(this.Close));
|
||
}
|
||
}
|
||
SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
|
||
}
|
||
else if (m.Msg == 0x30D) { // WM_CHANGECBCHAIN
|
||
if (m.WParam == nextClipboardViewer)
|
||
nextClipboardViewer = m.LParam;
|
||
else if (nextClipboardViewer != IntPtr.Zero)
|
||
SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
|
||
}
|
||
base.WndProc(ref m);
|
||
}
|
||
}
|
||
|
||
public static void ShowHelp() {
|
||
Console.WriteLine(@"Windows 监控工具使用说明
|
||
用法: monitor.exe -type <监控类型> [参数...]
|
||
|
||
监控类型:
|
||
clipboard - 剪贴板监控
|
||
参数:
|
||
-once 只监听一次变化就停止(可选)
|
||
示例:
|
||
monitor.exe -type clipboard -once
|
||
|
||
filesystem - 文件系统监控
|
||
参数:
|
||
-path <路径> 要监控的文件夹路径
|
||
-filter <过滤器> 文件过滤器,如 *.txt(可选,默认监控所有文件)
|
||
-recursive <bool> 是否监控子文件夹(可选,默认为 true)
|
||
-once 只监听一次变化就停止(可选)
|
||
示例:
|
||
monitor.exe -type filesystem -path C:\MyFolder -filter *.txt -recursive true -once
|
||
|
||
返回值:
|
||
监控到的变化会实时输出 JSON 格式的事件信息:
|
||
剪贴板事件:
|
||
{""type"": ""clipboard"", ""format"": ""文本/图片/文件"", ""content"": ""变化内容""}
|
||
文件系统事件:
|
||
{""type"": ""filesystem"", ""event"": ""created/changed/deleted/renamed"", ""path"": ""文件路径"", ""oldPath"": ""重命名前的路径""}
|
||
|
||
注意事项:
|
||
1. 按 Ctrl+C 停止监控
|
||
2. 剪贴板监控支持文本、图片和文件格式
|
||
3. 文件系统监控支持文件和文件夹的创建、修改、删除和重命名事件
|
||
4. 使用 -once 参数可以在监听到第一次变化后自动停止");
|
||
}
|
||
|
||
private static string GetArgumentValue(string[] args, string key) {
|
||
for (int i = 0; i < args.Length - 1; i++) {
|
||
if (args[i].Equals(key, StringComparison.OrdinalIgnoreCase)) {
|
||
return args[i + 1];
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
private static string EscapeJsonString(string str) {
|
||
if (str == null) return "null";
|
||
StringBuilder sb = new StringBuilder();
|
||
foreach (char c in str) {
|
||
switch (c) {
|
||
case '\"': sb.Append("\\\""); break;
|
||
case '\\': sb.Append("\\\\"); break;
|
||
case '\b': sb.Append("\\b"); break;
|
||
case '\f': sb.Append("\\f"); break;
|
||
case '\n': sb.Append("\\n"); break;
|
||
case '\r': sb.Append("\\r"); break;
|
||
case '\t': sb.Append("\\t"); break;
|
||
default:
|
||
if (c < ' ') {
|
||
sb.Append(string.Format("\\u{0:X4}", (int)c));
|
||
}
|
||
else {
|
||
sb.Append(c);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
return string.Format("\"{0}\"", sb.ToString());
|
||
}
|
||
|
||
private static void OutputEvent(string type, string format, string content) {
|
||
string json = string.Format("{{\"type\": {0}, \"format\": {1}, \"content\": {2}}}",
|
||
EscapeJsonString(type),
|
||
EscapeJsonString(format),
|
||
EscapeJsonString(content));
|
||
Console.WriteLine(json);
|
||
}
|
||
|
||
private static void OutputFileSystemEvent(string type, string eventType, string path, string oldPath = null) {
|
||
StringBuilder json = new StringBuilder();
|
||
json.Append("{\"type\": ").Append(EscapeJsonString(type));
|
||
json.Append(", \"event\": ").Append(EscapeJsonString(eventType));
|
||
json.Append(", \"path\": ").Append(EscapeJsonString(path));
|
||
if (oldPath != null) {
|
||
json.Append(", \"oldPath\": ").Append(EscapeJsonString(oldPath));
|
||
}
|
||
json.Append("}");
|
||
Console.WriteLine(json.ToString());
|
||
}
|
||
|
||
private static void StartClipboardMonitor() {
|
||
Thread thread = new Thread(() => {
|
||
clipboardForm = new ClipboardForm();
|
||
Application.Run(clipboardForm);
|
||
});
|
||
|
||
thread.SetApartmentState(ApartmentState.STA);
|
||
thread.Start();
|
||
}
|
||
|
||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
|
||
|
||
private static void HandleClipboardChanged() {
|
||
if (Clipboard.ContainsText()) {
|
||
OutputEvent("clipboard", "text", Clipboard.GetText());
|
||
}
|
||
else if (Clipboard.ContainsImage()) {
|
||
OutputEvent("clipboard", "image", "image_data");
|
||
}
|
||
else if (Clipboard.ContainsFileDropList()) {
|
||
OutputEvent("clipboard", "files", string.Join(", ", Clipboard.GetFileDropList().Cast<string>()));
|
||
}
|
||
}
|
||
|
||
private static void StartFileSystemMonitor(string path, string fileFilter, bool includeSubdirectories) {
|
||
fsWatcher = new FileSystemWatcher(path);
|
||
fsWatcher.Filter = fileFilter ?? "*.*";
|
||
fsWatcher.IncludeSubdirectories = includeSubdirectories;
|
||
|
||
FileSystemEventHandler handler = (s, e) => {
|
||
OutputFileSystemEvent("filesystem", e.ChangeType.ToString().ToLower(), e.FullPath);
|
||
if (listenOnce) {
|
||
running = false;
|
||
fsWatcher.Dispose();
|
||
}
|
||
};
|
||
|
||
RenamedEventHandler renameHandler = (s, e) => {
|
||
OutputFileSystemEvent("filesystem", "renamed", e.FullPath, e.OldFullPath);
|
||
if (listenOnce) {
|
||
running = false;
|
||
fsWatcher.Dispose();
|
||
}
|
||
};
|
||
|
||
fsWatcher.Created += handler;
|
||
fsWatcher.Changed += handler;
|
||
fsWatcher.Deleted += handler;
|
||
fsWatcher.Renamed += renameHandler;
|
||
|
||
fsWatcher.EnableRaisingEvents = true;
|
||
}
|
||
|
||
private static bool HasArgument(string[] args, string key) {
|
||
return Array.Exists(args, arg => arg.Equals(key, StringComparison.OrdinalIgnoreCase));
|
||
}
|
||
|
||
public static void Main(string[] args) {
|
||
if (args.Length == 0 || args[0] == "-h" || args[0] == "--help") {
|
||
ShowHelp();
|
||
return;
|
||
}
|
||
|
||
string type = GetArgumentValue(args, "-type");
|
||
if (string.IsNullOrEmpty(type)) {
|
||
Console.Error.WriteLine("Error: 必须指定监控类型 (-type)");
|
||
return;
|
||
}
|
||
|
||
listenOnce = HasArgument(args, "-once");
|
||
|
||
Console.CancelKeyPress += (s, e) => {
|
||
running = false;
|
||
if (fsWatcher != null) {
|
||
fsWatcher.Dispose();
|
||
}
|
||
if (clipboardForm != null) {
|
||
clipboardForm.Invoke(new Action(() => clipboardForm.Close()));
|
||
}
|
||
Environment.Exit(0);
|
||
};
|
||
|
||
try {
|
||
switch (type.ToLower()) {
|
||
case "clipboard":
|
||
StartClipboardMonitor();
|
||
break;
|
||
|
||
case "filesystem":
|
||
string path = GetArgumentValue(args, "-path");
|
||
if (string.IsNullOrEmpty(path)) {
|
||
Console.Error.WriteLine("Error: 必须指定监控路径 (-path)");
|
||
return;
|
||
}
|
||
|
||
string filter = GetArgumentValue(args, "-filter");
|
||
bool recursive = true;
|
||
string recursiveArg = GetArgumentValue(args, "-recursive");
|
||
if (!string.IsNullOrEmpty(recursiveArg)) {
|
||
recursive = bool.Parse(recursiveArg);
|
||
}
|
||
|
||
StartFileSystemMonitor(path, filter, recursive);
|
||
break;
|
||
|
||
default:
|
||
Console.Error.WriteLine(string.Format("Error: 不支持的监控类型: {0}", type));
|
||
return;
|
||
}
|
||
|
||
while (running) {
|
||
Thread.Sleep(100);
|
||
}
|
||
}
|
||
catch (Exception ex) {
|
||
Console.Error.WriteLine(string.Format("Error: {0}", ex.Message));
|
||
}
|
||
}
|
||
}
|