using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; 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; using AxCopilot.Views; namespace AxCopilot.Handlers; public class SystemCommandHandler : IActionHandler { private readonly SettingsService _settings; private static readonly Regex _timerRe = new Regex("^(?:(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?)$", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex _alarmRe = new Regex("^(\\d{1,2}):(\\d{2})$", RegexOptions.Compiled); public string? Prefix => "/"; public PluginMetadata Metadata => new PluginMetadata("SystemCommands", "시스템 명령 — / 뒤에 명령 입력", "1.0", "AX"); public SystemCommandHandler(SettingsService settings) { _settings = settings; } public Task> GetItemsAsync(string query, CancellationToken ct) { SystemCommandSettings cfg = _settings.Settings.SystemCommands; string q = query.Trim().ToLowerInvariant(); if (q.StartsWith("timer")) { string text = q; string text2 = text.Substring(5, text.Length - 5).Trim(); List list = new List(); if (string.IsNullOrEmpty(text2)) { list.Add(new LauncherItem("타이머 — 시간을 입력하세요", "예: /timer 5m · /timer 1h30m · /timer 30s 회의", null, null, null, "\ue916")); return Task.FromResult((IEnumerable)list); } string[] array = text2.Split(' ', 2); string s = array[0]; string label = ((array.Length > 1) ? array[1].Trim() : ""); if (TryParseTimer(s, out var seconds) && seconds > 0) { string display = FormatDuration(seconds); string title = (string.IsNullOrEmpty(label) ? ("타이머 " + display) : ("타이머 " + display + " — " + label)); list.Add(new LauncherItem(title, display + " 후 알림 · Enter로 시작", null, (Func)(() => StartTimerAsync(seconds, (label.Length > 0) ? label : display)), null, "\ue916")); } else { list.Add(new LauncherItem("형식 오류", "예: /timer 5m · /timer 1h30m · /timer 90s", null, null, null, "\uea39")); } return Task.FromResult((IEnumerable)list); } if (q.StartsWith("alarm")) { string text = q; string text3 = text.Substring(5, text.Length - 5).Trim(); List list2 = new List(); if (string.IsNullOrEmpty(text3)) { list2.Add(new LauncherItem("알람 — 시각을 입력하세요", "예: /alarm 14:30 · /alarm 9:00", null, null, null, "\ue916")); return Task.FromResult((IEnumerable)list2); } Match match = _alarmRe.Match(text3.Split(' ')[0]); if (match.Success) { int num = int.Parse(match.Groups[1].Value); int num2 = int.Parse(match.Groups[2].Value); object obj; if (!text3.Contains(' ')) { obj = ""; } else { text = text3; int num3 = text3.IndexOf(' ') + 1; obj = text.Substring(num3, text.Length - num3); } string label2 = (string)obj; if (num >= 0 && num <= 23 && num2 >= 0 && num2 <= 59) { DateTime dateTime = DateTime.Today.AddHours(num).AddMinutes(num2); if (dateTime <= DateTime.Now) { dateTime = dateTime.AddDays(1.0); } int diff = (int)(dateTime - DateTime.Now).TotalSeconds; string timeStr = dateTime.ToString("HH:mm"); list2.Add(new LauncherItem("알람 " + timeStr + " " + ((dateTime.Date > DateTime.Today) ? "(내일)" : ""), (FormatDuration(diff) + " 후 알림 · Enter로 시작 " + ((label2.Length > 0) ? ("— " + label2) : "")).Trim(), null, (Func)(() => StartTimerAsync(diff, (label2.Length > 0) ? label2 : (timeStr + " 알람"))), null, "\ue916")); } else { list2.Add(new LauncherItem("시각 범위 오류", "00:00 ~ 23:59 범위로 입력하세요", null, null, null, "\uea39")); } } else { list2.Add(new LauncherItem("형식 오류", "예: /alarm 14:30 · /alarm 09:00", null, null, null, "\uea39")); } return Task.FromResult((IEnumerable)list2); } List<(string, string, string, string, bool, Func)> list3 = new List<(string, string, string, string, bool, Func)>(); list3.Add(("lock", "화면 잠금", "현재 세션을 잠급니다", "\ue72e", cfg.ShowLock, LockAsync)); list3.Add(("sleep", "절전 모드", "시스템을 절전 상태로 전환합니다", "\uec46", cfg.ShowSleep, SleepAsync)); list3.Add(("restart", "재시작", "컴퓨터를 재시작합니다", "\ue777", cfg.ShowRestart, RestartAsync)); list3.Add(("shutdown", "시스템 종료", "컴퓨터를 종료합니다", "\ue7e8", cfg.ShowShutdown, ShutdownAsync)); list3.Add(("hibernate", "최대 절전", "최대 절전 모드로 전환합니다", "\uec46", cfg.ShowHibernate, HibernateAsync)); list3.Add(("logout", "로그아웃", "현재 사용자 세션에서 로그아웃합니다", "\uf3b1", cfg.ShowLogout, LogoutAsync)); list3.Add(("recycle", "휴지통 비우기", "휴지통의 모든 파일을 영구 삭제합니다", "\ue74d", cfg.ShowRecycleBin, EmptyRecycleBinAsync)); list3.Add(("dock", "독 바 표시/숨기기", "화면 하단 독 바를 표시하거나 숨깁니다", "\ue8a0", true, ToggleDockAsync)); List<(string, string, string, string, bool, Func)> source = list3; List value; IEnumerable source2 = from c in source where c.Enabled where string.IsNullOrEmpty(q) || c.Key.StartsWith(q) || c.Name.Contains(q) || (cfg.CommandAliases.TryGetValue(c.Key, out value) && value.Any((string a) => a.StartsWith(q, StringComparison.OrdinalIgnoreCase))) select new LauncherItem(c.Name, c.Hint, null, c.Action, null, c.Symbol); return Task.FromResult((IEnumerable)source2.ToList()); } public async Task ExecuteAsync(LauncherItem item, CancellationToken ct) { object data = item.Data; Func action = data as Func; if (action != null) { await action(); } } private static async Task StartTimerAsync(int totalSeconds, string label) { await Task.Delay(TimeSpan.FromSeconds(totalSeconds)); NotificationService.Notify("⏰ 타이머 완료", label); } private static bool TryParseTimer(string s, out int totalSeconds) { totalSeconds = 0; Match match = _timerRe.Match(s.ToLowerInvariant()); if (!match.Success) { return false; } int num = (match.Groups[1].Success ? int.Parse(match.Groups[1].Value) : 0); int num2 = (match.Groups[2].Success ? int.Parse(match.Groups[2].Value) : 0); int num3 = (match.Groups[3].Success ? int.Parse(match.Groups[3].Value) : 0); totalSeconds = num * 3600 + num2 * 60 + num3; return true; } private static string FormatDuration(int totalSeconds) { int num = totalSeconds / 3600; int num2 = totalSeconds % 3600 / 60; int num3 = totalSeconds % 60; if (num > 0 && num2 > 0) { return $"{num}시간 {num2}분"; } if (num <= 0) { if (num2 > 0 && num3 > 0) { return $"{num2}분 {num3}초"; } if (num2 <= 0) { return $"{num3}초"; } return $"{num2}분"; } return $"{num}시간"; } private static Task LockAsync() { LockWorkStation(); return Task.CompletedTask; } private static Task SleepAsync() { System.Windows.Forms.Application.SetSuspendState(PowerState.Suspend, force: false, disableWakeEvent: false); return Task.CompletedTask; } private static Task HibernateAsync() { System.Windows.Forms.Application.SetSuspendState(PowerState.Hibernate, force: false, disableWakeEvent: false); return Task.CompletedTask; } private static Task RestartAsync() { MessageBoxResult messageBoxResult = CustomMessageBox.Show("컴퓨터를 재시작하시겠습니까?\n저장되지 않은 작업이 있으면 먼저 저장하세요.", "재시작 확인", MessageBoxButton.YesNo, MessageBoxImage.Question); if (messageBoxResult == MessageBoxResult.Yes) { Process.Start(new ProcessStartInfo("shutdown", "/r /t 5 /c \"AX Copilot에 의해 재시작됩니다.\"") { UseShellExecute = true, CreateNoWindow = true }); } return Task.CompletedTask; } private static Task ShutdownAsync() { MessageBoxResult messageBoxResult = CustomMessageBox.Show("컴퓨터를 종료하시겠습니까?\n저장되지 않은 작업이 있으면 먼저 저장하세요.", "종료 확인", MessageBoxButton.YesNo, MessageBoxImage.Question); if (messageBoxResult == MessageBoxResult.Yes) { Process.Start(new ProcessStartInfo("shutdown", "/s /t 5 /c \"AX Copilot에 의해 종료됩니다.\"") { UseShellExecute = true, CreateNoWindow = true }); } return Task.CompletedTask; } private static Task LogoutAsync() { MessageBoxResult messageBoxResult = CustomMessageBox.Show("로그아웃하시겠습니까?", "로그아웃 확인", MessageBoxButton.YesNo, MessageBoxImage.Question); if (messageBoxResult == MessageBoxResult.Yes) { ExitWindowsEx(0u, 0u); } return Task.CompletedTask; } private static Task EmptyRecycleBinAsync() { MessageBoxResult messageBoxResult = CustomMessageBox.Show("휴지통을 비우시겠습니까?\n삭제된 파일은 복구할 수 없습니다.", "휴지통 비우기", MessageBoxButton.YesNo, MessageBoxImage.Exclamation); if (messageBoxResult == MessageBoxResult.Yes) { SHEmptyRecycleBin(IntPtr.Zero, null, 7u); } return Task.CompletedTask; } private static Task ToggleDockAsync() { ((DispatcherObject)System.Windows.Application.Current).Dispatcher.Invoke((Action)delegate { (System.Windows.Application.Current as App)?.ToggleDockBar(); }); return Task.CompletedTask; } [DllImport("user32.dll", SetLastError = true)] private static extern bool LockWorkStation(); [DllImport("user32.dll", SetLastError = true)] private static extern bool ExitWindowsEx(uint uFlags, uint dwReason); [DllImport("shell32.dll", CharSet = CharSet.Unicode)] private static extern uint SHEmptyRecycleBin(nint hwnd, string? pszRootPath, uint dwFlags); }