944 lines
27 KiB
C#
944 lines
27 KiB
C#
using System;
|
|
using System.CodeDom.Compiler;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Forms;
|
|
using System.Windows.Threading;
|
|
using AxCopilot.Core;
|
|
using AxCopilot.Handlers;
|
|
using AxCopilot.Models;
|
|
using AxCopilot.Security;
|
|
using AxCopilot.Services;
|
|
using AxCopilot.ViewModels;
|
|
using AxCopilot.Views;
|
|
using Microsoft.Win32;
|
|
|
|
namespace AxCopilot;
|
|
|
|
public class App : System.Windows.Application
|
|
{
|
|
private static class NativeMethods
|
|
{
|
|
public struct INPUT
|
|
{
|
|
public uint type;
|
|
|
|
public InputUnion u;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Explicit)]
|
|
public struct InputUnion
|
|
{
|
|
[FieldOffset(0)]
|
|
public KEYBDINPUT ki;
|
|
}
|
|
|
|
public struct KEYBDINPUT
|
|
{
|
|
public ushort wVk;
|
|
|
|
public ushort wScan;
|
|
|
|
public uint dwFlags;
|
|
|
|
public uint time;
|
|
|
|
public nint dwExtraInfo;
|
|
}
|
|
|
|
[DllImport("user32.dll")]
|
|
public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
|
|
}
|
|
|
|
[Serializable]
|
|
[CompilerGenerated]
|
|
private sealed class _003C_003Ec
|
|
{
|
|
public static readonly _003C_003Ec _003C_003E9 = new _003C_003Ec();
|
|
|
|
public static DispatcherUnhandledExceptionEventHandler _003C_003E9__24_0;
|
|
|
|
public static Action _003C_003E9__31_10;
|
|
|
|
public static Action _003C_003E9__31_17;
|
|
|
|
public static Action _003C_003E9__31_18;
|
|
|
|
public static Action<bool> _003C_003E9__31_13;
|
|
|
|
public static Action _003C_003E9__31_19;
|
|
|
|
internal void _003COnStartup_003Eb__24_0(object _, DispatcherUnhandledExceptionEventArgs ex)
|
|
{
|
|
LogService.Error($"미처리 예외: {ex.Exception}");
|
|
CustomMessageBox.Show("오류가 발생했습니다:\n" + ex.Exception.Message + "\n\n로그 폴더를 확인하세요.", "AX Copilot 오류", MessageBoxButton.OK, MessageBoxImage.Hand);
|
|
ex.Handled = true;
|
|
}
|
|
|
|
internal void _003CSetupTrayIcon_003Eb__31_10()
|
|
{
|
|
string arguments = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "logs");
|
|
Process.Start(new ProcessStartInfo("explorer.exe", arguments)
|
|
{
|
|
UseShellExecute = true
|
|
});
|
|
}
|
|
|
|
internal void _003CSetupTrayIcon_003Eb__31_17()
|
|
{
|
|
new StatisticsWindow().Show();
|
|
}
|
|
|
|
internal void _003CSetupTrayIcon_003Eb__31_18()
|
|
{
|
|
new GuideViewerWindow().Show();
|
|
}
|
|
|
|
internal void _003CSetupTrayIcon_003Eb__31_13(bool isChecked)
|
|
{
|
|
SetAutoStart(isChecked);
|
|
}
|
|
|
|
internal void _003CSetupTrayIcon_003Eb__31_19()
|
|
{
|
|
new AboutWindow().Show();
|
|
}
|
|
}
|
|
|
|
private Mutex? _singleInstanceMutex;
|
|
|
|
private InputListener? _inputListener;
|
|
|
|
private LauncherWindow? _launcher;
|
|
|
|
private NotifyIcon? _trayIcon;
|
|
|
|
private TrayMenuWindow? _trayMenu;
|
|
|
|
private SettingsService? _settings;
|
|
|
|
private SettingsWindow? _settingsWindow;
|
|
|
|
private PluginHost? _pluginHost;
|
|
|
|
private ClipboardHistoryService? _clipboardHistory;
|
|
|
|
private DockBarWindow? _dockBar;
|
|
|
|
private FileDialogWatcher? _fileDialogWatcher;
|
|
|
|
private volatile IndexService? _indexService;
|
|
|
|
private SessionTrackingService? _sessionTracking;
|
|
|
|
private WorktimeReminderService? _worktimeReminder;
|
|
|
|
private ScreenCaptureHandler? _captureHandler;
|
|
|
|
private AgentMemoryService? _memoryService;
|
|
|
|
private ChatWindow? _chatWindow;
|
|
|
|
private const string AutoRunKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
|
|
|
|
private const string AutoRunName = "AxCopilot";
|
|
|
|
private bool _contentLoaded;
|
|
|
|
public IndexService? IndexService => _indexService;
|
|
|
|
public SettingsService? SettingsService => _settings;
|
|
|
|
public ClipboardHistoryService? ClipboardHistoryService => _clipboardHistory;
|
|
|
|
public AgentMemoryService? MemoryService => _memoryService;
|
|
|
|
protected override void OnStartup(StartupEventArgs e)
|
|
{
|
|
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_003c: Expected O, but got Unknown
|
|
base.OnStartup(e);
|
|
AntiTamper.Check();
|
|
object obj = _003C_003Ec._003C_003E9__24_0;
|
|
if (obj == null)
|
|
{
|
|
DispatcherUnhandledExceptionEventHandler val = delegate(object _, DispatcherUnhandledExceptionEventArgs ex)
|
|
{
|
|
LogService.Error($"미처리 예외: {ex.Exception}");
|
|
CustomMessageBox.Show("오류가 발생했습니다:\n" + ex.Exception.Message + "\n\n로그 폴더를 확인하세요.", "AX Copilot 오류", MessageBoxButton.OK, MessageBoxImage.Hand);
|
|
ex.Handled = true;
|
|
};
|
|
_003C_003Ec._003C_003E9__24_0 = val;
|
|
obj = (object)val;
|
|
}
|
|
base.DispatcherUnhandledException += (DispatcherUnhandledExceptionEventHandler)obj;
|
|
_singleInstanceMutex = new Mutex(initiallyOwned: true, "Global\\AXCopilot_SingleInstance", out var createdNew);
|
|
if (!createdNew)
|
|
{
|
|
_singleInstanceMutex.Dispose();
|
|
_singleInstanceMutex = null;
|
|
CustomMessageBox.Show("AX Copilot가 이미 실행 중입니다.\n트레이 아이콘을 확인하세요.", "AX Copilot", MessageBoxButton.OK, MessageBoxImage.Asterisk);
|
|
Shutdown();
|
|
return;
|
|
}
|
|
LogService.Info("=== AX Copilot 시작 ===");
|
|
_settings = new SettingsService();
|
|
SettingsService settings = _settings;
|
|
settings.Load();
|
|
if (settings.MigrationSummary != null)
|
|
{
|
|
((DispatcherObject)this).Dispatcher.BeginInvoke((Delegate)(Action)delegate
|
|
{
|
|
CustomMessageBox.Show(settings.MigrationSummary, "AX Copilot — 설정 업데이트", MessageBoxButton.OK, MessageBoxImage.Asterisk);
|
|
}, (DispatcherPriority)6, Array.Empty<object>());
|
|
}
|
|
L10n.SetLanguage(settings.Settings.Launcher.Language);
|
|
if (!IsAutoStartEnabled())
|
|
{
|
|
SetAutoStart(enable: true);
|
|
}
|
|
_memoryService = new AgentMemoryService();
|
|
_memoryService.Load(settings.Settings.Llm.WorkFolder);
|
|
_indexService = new IndexService(settings);
|
|
IndexService indexService = _indexService;
|
|
FuzzyEngine fuzzy = new FuzzyEngine(indexService);
|
|
CommandResolver commandResolver = new CommandResolver(fuzzy, settings);
|
|
ContextManager context = new ContextManager(settings);
|
|
_sessionTracking = new SessionTrackingService();
|
|
_worktimeReminder = new WorktimeReminderService(settings, ((DispatcherObject)this).Dispatcher);
|
|
_clipboardHistory = new ClipboardHistoryService(settings);
|
|
commandResolver.RegisterHandler(new CalculatorHandler());
|
|
commandResolver.RegisterHandler(new SystemCommandHandler(settings));
|
|
commandResolver.RegisterHandler(new SnippetHandler(settings));
|
|
commandResolver.RegisterHandler(new ClipboardHistoryHandler(_clipboardHistory));
|
|
commandResolver.RegisterHandler(new WorkspaceHandler(context, settings));
|
|
commandResolver.RegisterHandler(new UrlAliasHandler(settings));
|
|
commandResolver.RegisterHandler(new FolderAliasHandler(settings));
|
|
commandResolver.RegisterHandler(new BatchHandler(settings));
|
|
commandResolver.RegisterHandler(new ClipboardHandler(settings));
|
|
commandResolver.RegisterHandler(new BookmarkHandler());
|
|
commandResolver.RegisterHandler(new WebSearchHandler(settings));
|
|
commandResolver.RegisterHandler(new ProcessHandler());
|
|
commandResolver.RegisterHandler(new MediaHandler());
|
|
commandResolver.RegisterHandler(new SystemInfoHandler());
|
|
commandResolver.RegisterHandler(new StarInfoHandler());
|
|
commandResolver.RegisterHandler(new EmojiHandler());
|
|
commandResolver.RegisterHandler(new ColorHandler());
|
|
commandResolver.RegisterHandler(new RecentFilesHandler());
|
|
commandResolver.RegisterHandler(new NoteHandler());
|
|
commandResolver.RegisterHandler(new UninstallHandler());
|
|
commandResolver.RegisterHandler(new PortHandler());
|
|
commandResolver.RegisterHandler(new EnvHandler());
|
|
commandResolver.RegisterHandler(new JsonHandler());
|
|
commandResolver.RegisterHandler(new EncodeHandler());
|
|
commandResolver.RegisterHandler(new SnapHandler());
|
|
_captureHandler = new ScreenCaptureHandler(settings);
|
|
commandResolver.RegisterHandler(_captureHandler);
|
|
commandResolver.RegisterHandler(new ColorPickHandler());
|
|
commandResolver.RegisterHandler(new DateCalcHandler());
|
|
commandResolver.RegisterHandler(new ServiceHandler(_clipboardHistory));
|
|
commandResolver.RegisterHandler(new ClipboardPipeHandler());
|
|
commandResolver.RegisterHandler(new JournalHandler());
|
|
commandResolver.RegisterHandler(new RoutineHandler());
|
|
commandResolver.RegisterHandler(new BatchTextHandler());
|
|
commandResolver.RegisterHandler(new DiffHandler(_clipboardHistory));
|
|
commandResolver.RegisterHandler(new WindowSwitchHandler());
|
|
commandResolver.RegisterHandler(new RunHandler());
|
|
commandResolver.RegisterHandler(new TextStatsHandler());
|
|
commandResolver.RegisterHandler(new FavoriteHandler());
|
|
commandResolver.RegisterHandler(new RenameHandler());
|
|
commandResolver.RegisterHandler(new MonitorHandler());
|
|
commandResolver.RegisterHandler(new ScaffoldHandler());
|
|
commandResolver.RegisterHandler(new EverythingHandler());
|
|
commandResolver.RegisterHandler(new HelpHandler(settings));
|
|
commandResolver.RegisterHandler(new ChatHandler(settings));
|
|
PluginHost pluginHost = new PluginHost(settings, commandResolver);
|
|
pluginHost.LoadAll();
|
|
_pluginHost = pluginHost;
|
|
LauncherViewModel vm = new LauncherViewModel(commandResolver, settings);
|
|
_launcher = new LauncherWindow(vm)
|
|
{
|
|
OpenSettingsAction = OpenSettings
|
|
};
|
|
((DispatcherObject)this).Dispatcher.BeginInvoke((Delegate)(Action)delegate
|
|
{
|
|
_clipboardHistory?.Initialize();
|
|
}, (DispatcherPriority)2, Array.Empty<object>());
|
|
((DispatcherObject)this).Dispatcher.BeginInvoke((Delegate)(Action)delegate
|
|
{
|
|
PrewarmChatWindow();
|
|
}, (DispatcherPriority)1, Array.Empty<object>());
|
|
indexService.BuildAsync().ContinueWith(delegate
|
|
{
|
|
indexService.StartWatchers();
|
|
});
|
|
_inputListener = new InputListener();
|
|
_inputListener.HotkeyTriggered += OnHotkeyTriggered;
|
|
_inputListener.CaptureHotkeyTriggered += OnCaptureHotkeyTriggered;
|
|
_inputListener.HookFailed += OnHookFailed;
|
|
_inputListener.UpdateHotkey(settings.Settings.Hotkey);
|
|
_inputListener.UpdateCaptureHotkey(settings.Settings.ScreenCapture.GlobalHotkey, settings.Settings.ScreenCapture.GlobalHotkeyEnabled);
|
|
SnippetExpander snippetExpander = new SnippetExpander(settings);
|
|
_inputListener.KeyFilter = snippetExpander.HandleKey;
|
|
_inputListener.Start();
|
|
SetupTrayIcon(pluginHost, settings);
|
|
_fileDialogWatcher = new FileDialogWatcher();
|
|
_fileDialogWatcher.FileDialogOpened += delegate
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
if (_launcher != null && !_launcher.IsVisible)
|
|
{
|
|
SettingsService? settings2 = _settings;
|
|
if (settings2 != null && settings2.Settings.Launcher.EnableFileDialogIntegration)
|
|
{
|
|
WindowTracker.Capture();
|
|
_launcher.Show();
|
|
((DispatcherObject)this).Dispatcher.BeginInvoke((DispatcherPriority)5, (Delegate)(Action)delegate
|
|
{
|
|
_launcher.SetInputText("cd ");
|
|
});
|
|
}
|
|
}
|
|
});
|
|
};
|
|
_fileDialogWatcher.Start();
|
|
if (settings.Settings.Launcher.DockBarAutoShow)
|
|
{
|
|
((DispatcherObject)this).Dispatcher.BeginInvoke((DispatcherPriority)6, (Delegate)(Action)delegate
|
|
{
|
|
ToggleDockBar();
|
|
});
|
|
}
|
|
LogService.Info("초기화 완료. " + settings.Settings.Hotkey + "로 실행하세요.");
|
|
}
|
|
|
|
private void OnHotkeyTriggered(object? sender, EventArgs e)
|
|
{
|
|
WindowTracker.Capture();
|
|
LauncherSettings launcherSettings = _settings?.Settings.Launcher;
|
|
bool flag = launcherSettings?.EnableTextAction ?? false;
|
|
bool isVisible = false;
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
isVisible = _launcher?.IsVisible ?? false;
|
|
});
|
|
if (isVisible)
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
_launcher?.Hide();
|
|
});
|
|
return;
|
|
}
|
|
if (!flag)
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
if (_launcher != null)
|
|
{
|
|
UsageStatisticsService.RecordLauncherOpen();
|
|
_launcher.Show();
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
string selectedText = TryGetSelectedText();
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
if (_launcher != null)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(selectedText))
|
|
{
|
|
List<string> enabledCmds = launcherSettings?.TextActionCommands ?? new List<string>();
|
|
if (enabledCmds.Count == 1 && !string.IsNullOrEmpty(TextActionPopup.AvailableCommands.FirstOrDefault<(string, string)>(((string Key, string Label) c) => c.Key == enabledCmds[0]).Item1))
|
|
{
|
|
string text = enabledCmds[0];
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
TextActionPopup.ActionResult actionResult = text switch
|
|
{
|
|
"translate" => TextActionPopup.ActionResult.Translate,
|
|
"summarize" => TextActionPopup.ActionResult.Summarize,
|
|
"grammar" => TextActionPopup.ActionResult.GrammarFix,
|
|
"explain" => TextActionPopup.ActionResult.Explain,
|
|
"rewrite" => TextActionPopup.ActionResult.Rewrite,
|
|
_ => TextActionPopup.ActionResult.None,
|
|
};
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
TextActionPopup.ActionResult actionResult2 = actionResult;
|
|
if (actionResult2 != TextActionPopup.ActionResult.None)
|
|
{
|
|
ExecuteTextAction(actionResult2, selectedText);
|
|
return;
|
|
}
|
|
}
|
|
TextActionPopup popup = new TextActionPopup(selectedText, enabledCmds);
|
|
popup.Closed += delegate
|
|
{
|
|
switch (popup.SelectedAction)
|
|
{
|
|
case TextActionPopup.ActionResult.OpenLauncher:
|
|
UsageStatisticsService.RecordLauncherOpen();
|
|
_launcher.Show();
|
|
break;
|
|
case TextActionPopup.ActionResult.None:
|
|
break;
|
|
default:
|
|
ExecuteTextAction(popup.SelectedAction, popup.SelectedText);
|
|
break;
|
|
}
|
|
};
|
|
popup.Show();
|
|
}
|
|
else
|
|
{
|
|
UsageStatisticsService.RecordLauncherOpen();
|
|
_launcher.Show();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private string? TryGetSelectedText()
|
|
{
|
|
try
|
|
{
|
|
string prevText = null;
|
|
bool hadText = false;
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
hadText = System.Windows.Clipboard.ContainsText();
|
|
prevText = (hadText ? System.Windows.Clipboard.GetText() : null);
|
|
System.Windows.Clipboard.Clear();
|
|
});
|
|
Thread.Sleep(30);
|
|
NativeMethods.INPUT[] array = new NativeMethods.INPUT[4]
|
|
{
|
|
new NativeMethods.INPUT
|
|
{
|
|
type = 1u,
|
|
u = new NativeMethods.InputUnion
|
|
{
|
|
ki = new NativeMethods.KEYBDINPUT
|
|
{
|
|
wVk = 17
|
|
}
|
|
}
|
|
},
|
|
new NativeMethods.INPUT
|
|
{
|
|
type = 1u,
|
|
u = new NativeMethods.InputUnion
|
|
{
|
|
ki = new NativeMethods.KEYBDINPUT
|
|
{
|
|
wVk = 67
|
|
}
|
|
}
|
|
},
|
|
new NativeMethods.INPUT
|
|
{
|
|
type = 1u,
|
|
u = new NativeMethods.InputUnion
|
|
{
|
|
ki = new NativeMethods.KEYBDINPUT
|
|
{
|
|
wVk = 67,
|
|
dwFlags = 2u
|
|
}
|
|
}
|
|
},
|
|
new NativeMethods.INPUT
|
|
{
|
|
type = 1u,
|
|
u = new NativeMethods.InputUnion
|
|
{
|
|
ki = new NativeMethods.KEYBDINPUT
|
|
{
|
|
wVk = 17,
|
|
dwFlags = 2u
|
|
}
|
|
}
|
|
}
|
|
};
|
|
NativeMethods.SendInput((uint)array.Length, array, Marshal.SizeOf<NativeMethods.INPUT>());
|
|
Thread.Sleep(80);
|
|
string selected = null;
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
if (System.Windows.Clipboard.ContainsText())
|
|
{
|
|
string text = System.Windows.Clipboard.GetText();
|
|
if (text != prevText && !string.IsNullOrWhiteSpace(text))
|
|
{
|
|
selected = text;
|
|
}
|
|
}
|
|
if (selected != null && prevText != null)
|
|
{
|
|
System.Windows.Clipboard.SetText(prevText);
|
|
}
|
|
else if (selected != null && !hadText)
|
|
{
|
|
System.Windows.Clipboard.Clear();
|
|
}
|
|
});
|
|
return selected;
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private void ExecuteTextAction(TextActionPopup.ActionResult action, string text)
|
|
{
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
string text2 = action switch
|
|
{
|
|
TextActionPopup.ActionResult.Translate => "다음 텍스트를 번역해줘:\n\n" + text,
|
|
TextActionPopup.ActionResult.Summarize => "다음 텍스트를 요약해줘:\n\n" + text,
|
|
TextActionPopup.ActionResult.GrammarFix => "다음 텍스트의 문법을 교정해줘:\n\n" + text,
|
|
TextActionPopup.ActionResult.Explain => "다음 텍스트를 쉽게 설명해줘:\n\n" + text,
|
|
TextActionPopup.ActionResult.Rewrite => "다음 텍스트를 다시 작성해줘:\n\n" + text,
|
|
_ => text,
|
|
};
|
|
if (1 == 0)
|
|
{
|
|
}
|
|
string text3 = text2;
|
|
_launcher?.Show();
|
|
_launcher?.SetInputText("! " + text3);
|
|
}
|
|
|
|
private void OnCaptureHotkeyTriggered(object? sender, EventArgs e)
|
|
{
|
|
WindowTracker.Capture();
|
|
string mode = _settings?.Settings.ScreenCapture.GlobalHotkeyMode ?? "screen";
|
|
((DispatcherObject)this).Dispatcher.Invoke<Task>((Func<Task>)async delegate
|
|
{
|
|
if (_captureHandler == null)
|
|
{
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
await _captureHandler.CaptureDirectAsync(mode);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogService.Error("글로벌 캡처 실패: " + ex.Message);
|
|
}
|
|
});
|
|
}
|
|
|
|
private void OnHookFailed(object? sender, EventArgs e)
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
_trayIcon?.ShowBalloonTip(3000, "AX Copilot", "글로벌 단축키 등록에 실패했습니다.\n다른 앱과 " + (_settings?.Settings.Hotkey ?? "단축키") + "가 충돌하고 있을 수 있습니다.", ToolTipIcon.Warning);
|
|
});
|
|
}
|
|
|
|
private void SetupTrayIcon(PluginHost pluginHost, SettingsService settings)
|
|
{
|
|
_trayIcon = new NotifyIcon
|
|
{
|
|
Text = "AX Copilot",
|
|
Visible = true,
|
|
Icon = LoadAppIcon()
|
|
};
|
|
_trayMenu = new TrayMenuWindow();
|
|
_trayMenu.AddItem("\ue7c5", "AX Commander 호출하기", delegate
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
_launcher?.Show();
|
|
});
|
|
}).AddItem("\ue8bd", "AX Agent 대화하기", delegate
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
OpenAiChat();
|
|
});
|
|
}, out Border aiTrayItem).AddItem("\ue8a7", "독 바 표시", delegate
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
ToggleDockBar();
|
|
});
|
|
})
|
|
.AddSeparator()
|
|
.AddItem("\ue72c", "플러그인 재로드", delegate
|
|
{
|
|
pluginHost.Reload();
|
|
_trayIcon.ShowBalloonTip(2000, "AX Copilot", "플러그인이 재로드되었습니다.", ToolTipIcon.None);
|
|
})
|
|
.AddItem("\ue838", "로그 폴더 열기", delegate
|
|
{
|
|
string arguments = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "logs");
|
|
Process.Start(new ProcessStartInfo("explorer.exe", arguments)
|
|
{
|
|
UseShellExecute = true
|
|
});
|
|
})
|
|
.AddItem("\ue9d9", "사용 통계", delegate
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
new StatisticsWindow().Show();
|
|
});
|
|
})
|
|
.AddItem("\ue736", "사용 가이드 문서보기", delegate
|
|
{
|
|
try
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
new GuideViewerWindow().Show();
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogService.Error("사용 가이드 열기 실패: " + ex.Message);
|
|
}
|
|
})
|
|
.AddSeparator()
|
|
.AddToggleItem("\ue82f", "Windows 시작 시 자동 실행", IsAutoStartEnabled(), delegate(bool isChecked)
|
|
{
|
|
SetAutoStart(isChecked);
|
|
}, out Func<bool> _, out Action<string> _)
|
|
.AddSeparator()
|
|
.AddItem("\ue713", "설정", delegate
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)OpenSettings);
|
|
})
|
|
.AddItem("\ue946", "개발 정보", delegate
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
new AboutWindow().Show();
|
|
});
|
|
})
|
|
.AddItem("\ue711", "종료", delegate
|
|
{
|
|
_inputListener?.Dispose();
|
|
_trayIcon?.Dispose();
|
|
Shutdown();
|
|
});
|
|
_trayMenu.Opening += delegate
|
|
{
|
|
aiTrayItem.Visibility = ((!settings.Settings.AiEnabled) ? Visibility.Collapsed : Visibility.Visible);
|
|
};
|
|
_trayIcon.MouseClick += delegate(object? _, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
_launcher?.Show();
|
|
});
|
|
}
|
|
else if (e.Button == MouseButtons.Right)
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
_trayMenu?.ShowWithUpdate();
|
|
});
|
|
}
|
|
};
|
|
NotificationService.Initialize(delegate(string title, string msg)
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)delegate
|
|
{
|
|
_trayIcon?.ShowBalloonTip(4000, title, msg, ToolTipIcon.None);
|
|
});
|
|
});
|
|
}
|
|
|
|
public void OpenSettingsFromChat()
|
|
{
|
|
((DispatcherObject)this).Dispatcher.Invoke((Action)OpenSettings);
|
|
}
|
|
|
|
internal void PrewarmChatWindow()
|
|
{
|
|
if (_chatWindow == null && _settings != null)
|
|
{
|
|
_chatWindow = new ChatWindow(_settings);
|
|
}
|
|
}
|
|
|
|
private void OpenAiChat()
|
|
{
|
|
if (_settings != null)
|
|
{
|
|
if (_chatWindow == null)
|
|
{
|
|
_chatWindow = new ChatWindow(_settings);
|
|
}
|
|
_chatWindow.Show();
|
|
_chatWindow.Activate();
|
|
}
|
|
}
|
|
|
|
public void ToggleDockBar()
|
|
{
|
|
if (_dockBar != null && _dockBar.IsVisible)
|
|
{
|
|
_dockBar.Hide();
|
|
return;
|
|
}
|
|
if (_dockBar == null)
|
|
{
|
|
_dockBar = new DockBarWindow();
|
|
_dockBar.OnQuickSearch = delegate(string query)
|
|
{
|
|
if (_launcher != null)
|
|
{
|
|
_launcher.Show();
|
|
_launcher.Activate();
|
|
if (!string.IsNullOrEmpty(query))
|
|
{
|
|
((DispatcherObject)this).Dispatcher.BeginInvoke((DispatcherPriority)5, (Delegate)(Action)delegate
|
|
{
|
|
_launcher.SetInputText(query);
|
|
});
|
|
}
|
|
}
|
|
};
|
|
_dockBar.OnCapture = async delegate
|
|
{
|
|
WindowTracker.Capture();
|
|
if (_captureHandler != null)
|
|
{
|
|
await _captureHandler.CaptureDirectAsync("region");
|
|
}
|
|
};
|
|
_dockBar.OnOpenAgent = delegate
|
|
{
|
|
if (_launcher != null)
|
|
{
|
|
_launcher.Show();
|
|
((DispatcherObject)this).Dispatcher.BeginInvoke((DispatcherPriority)5, (Delegate)(Action)delegate
|
|
{
|
|
_launcher.SetInputText("!");
|
|
});
|
|
}
|
|
};
|
|
}
|
|
LauncherSettings launcherSettings = _settings?.Settings.Launcher;
|
|
List<string> itemKeys = launcherSettings?.DockBarItems ?? new List<string> { "launcher", "clipboard", "capture", "agent", "clock", "cpu" };
|
|
_dockBar.BuildFromSettings(itemKeys);
|
|
_dockBar.OnPositionChanged = delegate(double left, double top)
|
|
{
|
|
if (_settings != null)
|
|
{
|
|
_settings.Settings.Launcher.DockBarLeft = left;
|
|
_settings.Settings.Launcher.DockBarTop = top;
|
|
_settings.Save();
|
|
}
|
|
};
|
|
_dockBar.Show();
|
|
_dockBar.ApplySettings(launcherSettings?.DockBarOpacity ?? 0.92, launcherSettings?.DockBarLeft ?? (-1.0), launcherSettings?.DockBarTop ?? (-1.0), launcherSettings?.DockBarRainbowGlow ?? false);
|
|
}
|
|
|
|
public void RefreshDockBar()
|
|
{
|
|
if (_dockBar != null && _dockBar.IsVisible)
|
|
{
|
|
LauncherSettings launcherSettings = _settings?.Settings.Launcher;
|
|
List<string> itemKeys = launcherSettings?.DockBarItems ?? new List<string> { "launcher", "clipboard", "capture", "agent", "clock", "cpu" };
|
|
_dockBar.BuildFromSettings(itemKeys);
|
|
_dockBar.ApplySettings(launcherSettings?.DockBarOpacity ?? 0.92, launcherSettings?.DockBarLeft ?? (-1.0), launcherSettings?.DockBarTop ?? (-1.0), launcherSettings?.DockBarRainbowGlow ?? false);
|
|
}
|
|
}
|
|
|
|
private void OpenSettings()
|
|
{
|
|
SettingsViewModel vm;
|
|
if (_settingsWindow != null && _settingsWindow.IsVisible)
|
|
{
|
|
_settingsWindow.Activate();
|
|
}
|
|
else
|
|
{
|
|
if (_settings == null || _launcher == null)
|
|
{
|
|
return;
|
|
}
|
|
vm = new SettingsViewModel(_settings);
|
|
_settingsWindow = new SettingsWindow(vm, PreviewCallback, RevertCallback)
|
|
{
|
|
SuspendHotkeyCallback = delegate(bool suspend)
|
|
{
|
|
if (_inputListener != null)
|
|
{
|
|
_inputListener.SuspendHotkey = suspend;
|
|
}
|
|
}
|
|
};
|
|
vm.SaveCompleted += delegate
|
|
{
|
|
if (_inputListener != null && _settings != null)
|
|
{
|
|
_inputListener.UpdateHotkey(_settings.Settings.Hotkey);
|
|
_inputListener.UpdateCaptureHotkey(_settings.Settings.ScreenCapture.GlobalHotkey, _settings.Settings.ScreenCapture.GlobalHotkeyEnabled);
|
|
}
|
|
_worktimeReminder?.RestartTimer();
|
|
};
|
|
_settingsWindow.Show();
|
|
}
|
|
void PreviewCallback(string themeKey)
|
|
{
|
|
if (themeKey == "custom")
|
|
{
|
|
CustomThemeColors customThemeColors = new CustomThemeColors();
|
|
foreach (ColorRowModel colorRow in vm.ColorRows)
|
|
{
|
|
typeof(CustomThemeColors).GetProperty(colorRow.Property)?.SetValue(customThemeColors, colorRow.Hex);
|
|
}
|
|
_launcher.ApplyTheme(themeKey, customThemeColors);
|
|
}
|
|
else
|
|
{
|
|
_launcher.ApplyTheme(themeKey, _settings.Settings.Launcher.CustomTheme);
|
|
}
|
|
}
|
|
void RevertCallback()
|
|
{
|
|
_launcher.ApplyTheme(_settings.Settings.Launcher.Theme ?? "system", _settings.Settings.Launcher.CustomTheme);
|
|
}
|
|
}
|
|
|
|
private static Icon LoadAppIcon()
|
|
{
|
|
Size smallIconSize = SystemInformation.SmallIconSize;
|
|
try
|
|
{
|
|
string path = Path.GetDirectoryName(Environment.ProcessPath) ?? AppContext.BaseDirectory;
|
|
string text = Path.Combine(path, "Assets", "icon.ico");
|
|
if (File.Exists(text))
|
|
{
|
|
return new Icon(text, smallIconSize);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
try
|
|
{
|
|
Uri uriResource = new Uri("pack://application:,,,/Assets/icon.ico");
|
|
Stream stream = System.Windows.Application.GetResourceStream(uriResource)?.Stream;
|
|
if (stream != null)
|
|
{
|
|
return new Icon(stream, smallIconSize);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
return SystemIcons.Application;
|
|
}
|
|
|
|
private static bool IsAutoStartEnabled()
|
|
{
|
|
try
|
|
{
|
|
using RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run", writable: false);
|
|
return registryKey?.GetValue("AxCopilot") != null;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static void SetAutoStart(bool enable)
|
|
{
|
|
try
|
|
{
|
|
using RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run", writable: true);
|
|
if (registryKey == null)
|
|
{
|
|
return;
|
|
}
|
|
if (enable)
|
|
{
|
|
string text = Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
|
|
if (!string.IsNullOrEmpty(text))
|
|
{
|
|
registryKey.SetValue("AxCopilot", "\"" + text + "\"");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
registryKey.DeleteValue("AxCopilot", throwOnMissingValue: false);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogService.Warn("자동 시작 레지스트리 설정 실패: " + ex.Message);
|
|
}
|
|
}
|
|
|
|
protected override void OnExit(ExitEventArgs e)
|
|
{
|
|
_chatWindow?.ForceClose();
|
|
_inputListener?.Dispose();
|
|
_clipboardHistory?.Dispose();
|
|
_indexService?.Dispose();
|
|
_sessionTracking?.Dispose();
|
|
_worktimeReminder?.Dispose();
|
|
_trayIcon?.Dispose();
|
|
try
|
|
{
|
|
_singleInstanceMutex?.ReleaseMutex();
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
_singleInstanceMutex?.Dispose();
|
|
LogService.Info("=== AX Copilot 종료 ===");
|
|
base.OnExit(e);
|
|
}
|
|
|
|
[DebuggerNonUserCode]
|
|
[GeneratedCode("PresentationBuildTasks", "10.0.5.0")]
|
|
public void InitializeComponent()
|
|
{
|
|
if (!_contentLoaded)
|
|
{
|
|
_contentLoaded = true;
|
|
Uri resourceLocator = new Uri("/AxCopilot;component/app.xaml", UriKind.Relative);
|
|
System.Windows.Application.LoadComponent(this, resourceLocator);
|
|
}
|
|
}
|
|
|
|
[STAThread]
|
|
[DebuggerNonUserCode]
|
|
[GeneratedCode("PresentationBuildTasks", "10.0.5.0")]
|
|
public static void Main()
|
|
{
|
|
App app = new App();
|
|
app.InitializeComponent();
|
|
app.Run();
|
|
}
|
|
}
|