300 lines
7.6 KiB
C#
300 lines
7.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using System.Windows.Forms;
|
|
using System.Windows.Threading;
|
|
using AxCopilot.Models;
|
|
using AxCopilot.SDK;
|
|
using AxCopilot.Services;
|
|
|
|
namespace AxCopilot.Handlers;
|
|
|
|
public class ClipboardHandler : IActionHandler
|
|
{
|
|
private readonly SettingsService _settings;
|
|
|
|
public string? Prefix => "$";
|
|
|
|
public PluginMetadata Metadata => new PluginMetadata("clipboard", "클립보드 변환", "1.0", "AX");
|
|
|
|
public ClipboardHandler(SettingsService settings)
|
|
{
|
|
_settings = settings;
|
|
}
|
|
|
|
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
|
|
{
|
|
List<LauncherItem> list = new List<LauncherItem>();
|
|
IEnumerable<ClipboardTransformer> enumerable = from t in GetBuiltinTransformers()
|
|
where string.IsNullOrEmpty(query) || t.Key.Contains(query, StringComparison.OrdinalIgnoreCase)
|
|
select t;
|
|
foreach (ClipboardTransformer item in enumerable)
|
|
{
|
|
list.Add(new LauncherItem(item.Key, item.Description ?? "", null, item, null, "\ue77f"));
|
|
}
|
|
IEnumerable<LauncherItem> collection = from t in _settings.Settings.ClipboardTransformers
|
|
where string.IsNullOrEmpty(query) || t.Key.Contains(query, StringComparison.OrdinalIgnoreCase)
|
|
select new LauncherItem(t.Key, t.Description ?? t.Type, null, t, null, "\ue77f");
|
|
list.AddRange(collection);
|
|
return Task.FromResult((IEnumerable<LauncherItem>)list);
|
|
}
|
|
|
|
public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)
|
|
{
|
|
object data = item.Data;
|
|
if (!(data is ClipboardTransformer transformer))
|
|
{
|
|
return;
|
|
}
|
|
string input = null;
|
|
((DispatcherObject)System.Windows.Application.Current).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
input = (System.Windows.Clipboard.ContainsText() ? System.Windows.Clipboard.GetText() : null);
|
|
});
|
|
if (input == null)
|
|
{
|
|
return;
|
|
}
|
|
string result = await TransformAsync(transformer, input, ct);
|
|
if (result != null)
|
|
{
|
|
((DispatcherObject)System.Windows.Application.Current).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
System.Windows.Clipboard.SetText(result);
|
|
});
|
|
nint prevHwnd = WindowTracker.PreviousWindow;
|
|
if (prevHwnd != IntPtr.Zero)
|
|
{
|
|
SetForegroundWindow(prevHwnd);
|
|
}
|
|
await Task.Delay(120, ct);
|
|
SendKeys.SendWait("^v");
|
|
LogService.Info("클립보드 변환: '" + transformer.Key + "' 적용");
|
|
}
|
|
}
|
|
|
|
private static async Task<string?> TransformAsync(ClipboardTransformer t, string input, CancellationToken ct)
|
|
{
|
|
try
|
|
{
|
|
string type = t.Type;
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
string text = type;
|
|
string result;
|
|
if (!(text == "regex"))
|
|
{
|
|
if (!(text == "script") || t.Command == null)
|
|
{
|
|
goto IL_016f;
|
|
}
|
|
result = await RunScriptAsync(t.Command, input, t.Timeout, ct);
|
|
}
|
|
else
|
|
{
|
|
if (t.Pattern == null || t.Replace == null)
|
|
{
|
|
goto IL_016f;
|
|
}
|
|
result = Regex.Replace(input, t.Pattern, t.Replace, RegexOptions.None, TimeSpan.FromMilliseconds((t.Timeout > 0) ? t.Timeout : 5000));
|
|
}
|
|
goto IL_0188;
|
|
IL_016f:
|
|
result = ExecuteBuiltin(t.Key, input);
|
|
goto IL_0188;
|
|
IL_0188:
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
return result;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Exception ex2 = ex;
|
|
LogService.Error("변환 실패 (" + t.Key + "): " + ex2.Message);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static async Task<string> RunScriptAsync(string command, string input, int timeoutMs, CancellationToken ct)
|
|
{
|
|
using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
|
|
cts.CancelAfter(timeoutMs);
|
|
string[] parts = command.Split(' ', 2);
|
|
ProcessStartInfo psi = new ProcessStartInfo(parts[0])
|
|
{
|
|
Arguments = ((parts.Length > 1) ? parts[1] : ""),
|
|
RedirectStandardInput = true,
|
|
RedirectStandardOutput = true,
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true,
|
|
StandardInputEncoding = Encoding.UTF8,
|
|
StandardOutputEncoding = Encoding.UTF8
|
|
};
|
|
using Process proc = Process.Start(psi);
|
|
await proc.StandardInput.WriteAsync(input);
|
|
proc.StandardInput.Close();
|
|
return await proc.StandardOutput.ReadToEndAsync(cts.Token);
|
|
}
|
|
|
|
internal static string? ExecuteBuiltin(string key, string input)
|
|
{
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
string result = key switch
|
|
{
|
|
"$json" => FormatJson(input),
|
|
"$upper" => input.ToUpperInvariant(),
|
|
"$lower" => input.ToLowerInvariant(),
|
|
"$ts" => TryParseTimestamp(input),
|
|
"$epoch" => TryParseDate(input),
|
|
"$urle" => Uri.EscapeDataString(input),
|
|
"$urld" => Uri.UnescapeDataString(input),
|
|
"$b64e" => Convert.ToBase64String(Encoding.UTF8.GetBytes(input)),
|
|
"$b64d" => Encoding.UTF8.GetString(Convert.FromBase64String(input)),
|
|
"$md" => StripMarkdown(input),
|
|
"$trim" => input.Trim(),
|
|
"$lines" => string.Join(Environment.NewLine, from l in input.Split('\n')
|
|
select l.Trim() into l
|
|
where l.Length > 0
|
|
select l),
|
|
_ => null,
|
|
};
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static string FormatJson(string input)
|
|
{
|
|
try
|
|
{
|
|
JsonDocument value = JsonDocument.Parse(input);
|
|
return JsonSerializer.Serialize(value, new JsonSerializerOptions
|
|
{
|
|
WriteIndented = true
|
|
});
|
|
}
|
|
catch
|
|
{
|
|
return input;
|
|
}
|
|
}
|
|
|
|
private static string? TryParseTimestamp(string input)
|
|
{
|
|
if (long.TryParse(input.Trim(), out var result))
|
|
{
|
|
return DateTimeOffset.FromUnixTimeSeconds(result).LocalDateTime.ToString("yyyy-MM-dd HH:mm:ss");
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static string? TryParseDate(string input)
|
|
{
|
|
if (DateTime.TryParse(input.Trim(), out var result))
|
|
{
|
|
return new DateTimeOffset(result).ToUnixTimeSeconds().ToString();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static string StripMarkdown(string input)
|
|
{
|
|
return Regex.Replace(input, "(\\*\\*|__)(.*?)\\1|(\\*|_)(.*?)\\3|`(.+?)`|#{1,6}\\s*", "$2$4$5");
|
|
}
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern bool SetForegroundWindow(nint hWnd);
|
|
|
|
private static IEnumerable<ClipboardTransformer> GetBuiltinTransformers()
|
|
{
|
|
return new _003C_003Ez__ReadOnlyArray<ClipboardTransformer>(new ClipboardTransformer[12]
|
|
{
|
|
new ClipboardTransformer
|
|
{
|
|
Key = "$json",
|
|
Type = "builtin",
|
|
Description = "JSON 포맷팅 (들여쓰기 적용)"
|
|
},
|
|
new ClipboardTransformer
|
|
{
|
|
Key = "$upper",
|
|
Type = "builtin",
|
|
Description = "대문자 변환"
|
|
},
|
|
new ClipboardTransformer
|
|
{
|
|
Key = "$lower",
|
|
Type = "builtin",
|
|
Description = "소문자 변환"
|
|
},
|
|
new ClipboardTransformer
|
|
{
|
|
Key = "$ts",
|
|
Type = "builtin",
|
|
Description = "유닉스 타임스탬프 → 날짜 문자열"
|
|
},
|
|
new ClipboardTransformer
|
|
{
|
|
Key = "$epoch",
|
|
Type = "builtin",
|
|
Description = "날짜 문자열 → 유닉스 타임스탬프"
|
|
},
|
|
new ClipboardTransformer
|
|
{
|
|
Key = "$urle",
|
|
Type = "builtin",
|
|
Description = "URL 인코딩"
|
|
},
|
|
new ClipboardTransformer
|
|
{
|
|
Key = "$urld",
|
|
Type = "builtin",
|
|
Description = "URL 디코딩"
|
|
},
|
|
new ClipboardTransformer
|
|
{
|
|
Key = "$b64e",
|
|
Type = "builtin",
|
|
Description = "Base64 인코딩"
|
|
},
|
|
new ClipboardTransformer
|
|
{
|
|
Key = "$b64d",
|
|
Type = "builtin",
|
|
Description = "Base64 디코딩"
|
|
},
|
|
new ClipboardTransformer
|
|
{
|
|
Key = "$md",
|
|
Type = "builtin",
|
|
Description = "마크다운 문법 제거"
|
|
},
|
|
new ClipboardTransformer
|
|
{
|
|
Key = "$trim",
|
|
Type = "builtin",
|
|
Description = "앞뒤 공백 제거"
|
|
},
|
|
new ClipboardTransformer
|
|
{
|
|
Key = "$lines",
|
|
Type = "builtin",
|
|
Description = "빈 줄 제거 및 각 줄 공백 정리"
|
|
}
|
|
});
|
|
}
|
|
}
|