271 lines
10 KiB
C#
271 lines
10 KiB
C#
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<IEnumerable<LauncherItem>> 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<LauncherItem> list = new List<LauncherItem>();
|
|
if (string.IsNullOrEmpty(text2))
|
|
{
|
|
list.Add(new LauncherItem("타이머 — 시간을 입력하세요", "예: /timer 5m · /timer 1h30m · /timer 30s 회의", null, null, null, "\ue916"));
|
|
return Task.FromResult((IEnumerable<LauncherItem>)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<Task>)(() => 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<LauncherItem>)list);
|
|
}
|
|
if (q.StartsWith("alarm"))
|
|
{
|
|
string text = q;
|
|
string text3 = text.Substring(5, text.Length - 5).Trim();
|
|
List<LauncherItem> list2 = new List<LauncherItem>();
|
|
if (string.IsNullOrEmpty(text3))
|
|
{
|
|
list2.Add(new LauncherItem("알람 — 시각을 입력하세요", "예: /alarm 14:30 · /alarm 9:00", null, null, null, "\ue916"));
|
|
return Task.FromResult((IEnumerable<LauncherItem>)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<Task>)(() => 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<LauncherItem>)list2);
|
|
}
|
|
List<(string, string, string, string, bool, Func<Task>)> list3 = new List<(string, string, string, string, bool, Func<Task>)>();
|
|
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<Task>)> source = list3;
|
|
List<string> value;
|
|
IEnumerable<LauncherItem> 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<LauncherItem>)source2.ToList());
|
|
}
|
|
|
|
public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)
|
|
{
|
|
object data = item.Data;
|
|
Func<Task> action = data as Func<Task>;
|
|
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);
|
|
}
|