Phase L2-4: 클립보드 이미지 OCR 텍스트 추출 및 검색 - AxCopilot.csproj: TFM net8.0-windows → net8.0-windows10.0.17763.0 (Windows OCR API 활성화) - ClipboardEntry: OcrText 프로퍼티 추가 (set), Preview → OCR 텍스트 우선 표시 (72자 상한) - SavedClipEntry: OcrText 직렬화 필드 추가, BuildSnapshot/LoadHistory 연동 - ClipboardHistoryService.OnClipboardUpdate: 이미지 저장 후 백그라운드 OCR 트리거 (EnableOcrSearch 설정 체크, capturedEntry.OcrText 비동기 갱신) - ClipboardHistoryService.ImageCache.cs: ExtractOcrTextAsync() 추가 (WinRT BitmapDecoder → SoftwareBitmap → OcrEngine.RecognizeAsync, 5,000자 상한) WinRT 별칭(WinBitmapDecoder, WinSoftwareBitmap 등) 으로 WPF 네임스페이스 충돌 방지 - AppSettings.Models.cs: ClipboardHistorySettings.EnableOcrSearch (default=true) - ClipboardHistoryHandler.GetItemsAsync: OcrText 포함 검색, 'OCR ·' 표시 배지 Phase L2-5: Ctrl+Click 클립보드 항목 다중 선택 - LauncherWindow.Shell.cs: ResultList_PreviewMouseLeftButtonUp에 Ctrl+Click 분기 추가 (IsClipboardMode + Ctrl 조합 시 ToggleMergeItem 호출, 기존 단일 선택 흐름 유지) - LauncherWindow.ShortcutHelp.cs: Ctrl+Click / Shift+↑↓ / 병합 단축키 도움말 추가 빌드: 경고 0, 오류 0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
152 lines
5.7 KiB
C#
152 lines
5.7 KiB
C#
using System.Windows;
|
|
using System.Windows.Input;
|
|
using AxCopilot.Services;
|
|
using AxCopilot.ViewModels;
|
|
|
|
namespace AxCopilot.Views;
|
|
|
|
public partial class LauncherWindow
|
|
{
|
|
// ─── 단축키 도움말 + 토스트 + 특수 액션 ────────────────────────────────────
|
|
|
|
/// <summary>단축키 도움말 팝업</summary>
|
|
private void ShowShortcutHelp()
|
|
{
|
|
var lines = new[]
|
|
{
|
|
"[ 전역 ]",
|
|
"Alt+Space AX Commander 열기/닫기",
|
|
"",
|
|
"[ 탐색 ]",
|
|
"↑ / ↓ 결과 이동",
|
|
"Enter 선택 실행",
|
|
"Tab 자동완성",
|
|
"→ 액션 모드",
|
|
"Escape 닫기 / 뒤로",
|
|
"",
|
|
"[ 기능 ]",
|
|
"F1 도움말",
|
|
"F2 파일 이름 바꾸기",
|
|
"F5 인덱스 새로 고침",
|
|
"Delete 항목 제거",
|
|
"Ctrl+, 설정",
|
|
"Ctrl+L 입력 초기화",
|
|
"Ctrl+C 이름 복사",
|
|
"Ctrl+H 클립보드 히스토리",
|
|
"Ctrl+R 최근 실행",
|
|
"Ctrl+B 즐겨찾기",
|
|
"Ctrl+K 이 도움말",
|
|
"Ctrl+1~9 N번째 실행",
|
|
"Ctrl+Shift+C 경로 복사",
|
|
"Ctrl+Shift+E 탐색기에서 열기",
|
|
"Ctrl+Enter 관리자 실행",
|
|
"Alt+Enter 속성 보기",
|
|
"Shift+Enter 대형 텍스트 / 이미지 미리보기 (#)",
|
|
"Ctrl+Click 클립보드 항목 다중 선택 (#)",
|
|
"Shift+↑/↓ 클립보드 항목 선택/해제 (#)",
|
|
"Shift+Enter 선택 항목 병합 (MergeCount > 0)",
|
|
};
|
|
|
|
CustomMessageBox.Show(
|
|
string.Join("\n", lines),
|
|
"AX Commander — 단축키 도움말",
|
|
MessageBoxButton.OK,
|
|
MessageBoxImage.Information);
|
|
}
|
|
|
|
// ─── 토스트 알림 ──────────────────────────────────────────────────────────
|
|
|
|
/// <summary>오버레이 토스트 표시 (페이드인 → 2초 대기 → 페이드아웃)</summary>
|
|
private void ShowToast(string message, string icon = "\uE73E")
|
|
{
|
|
ToastText.Text = message;
|
|
ToastIcon.Text = icon;
|
|
ToastOverlay.Visibility = Visibility.Visible;
|
|
ToastOverlay.Opacity = 0;
|
|
|
|
// 페이드인
|
|
var fadeIn = (System.Windows.Media.Animation.Storyboard)FindResource("ToastFadeIn");
|
|
fadeIn.Begin(this);
|
|
|
|
_indexStatusTimer?.Stop();
|
|
_indexStatusTimer = new System.Windows.Threading.DispatcherTimer
|
|
{
|
|
Interval = TimeSpan.FromSeconds(2)
|
|
};
|
|
_indexStatusTimer.Tick += (_, _) =>
|
|
{
|
|
_indexStatusTimer.Stop();
|
|
// 페이드아웃 후 Collapsed
|
|
var fadeOut = (System.Windows.Media.Animation.Storyboard)FindResource("ToastFadeOut");
|
|
EventHandler? onCompleted = null;
|
|
onCompleted = (__, ___) =>
|
|
{
|
|
fadeOut.Completed -= onCompleted;
|
|
ToastOverlay.Visibility = Visibility.Collapsed;
|
|
};
|
|
fadeOut.Completed += onCompleted;
|
|
fadeOut.Begin(this);
|
|
};
|
|
_indexStatusTimer.Start();
|
|
}
|
|
|
|
// ─── 특수 액션 처리 ───────────────────────────────────────────────────────
|
|
|
|
/// <summary>
|
|
/// 액션 모드에서 특수 처리가 필요한 동작(삭제/이름변경)을 처리합니다.
|
|
/// 처리되면 true 반환 → ExecuteSelectedAsync 호출 생략.
|
|
/// </summary>
|
|
private bool TryHandleSpecialAction()
|
|
{
|
|
if (_vm.SelectedItem?.Data is not AxCopilot.ViewModels.FileActionData actionData)
|
|
return false;
|
|
|
|
switch (actionData.Action)
|
|
{
|
|
case AxCopilot.ViewModels.FileAction.DeleteToRecycleBin:
|
|
{
|
|
var path = actionData.Path;
|
|
var name = System.IO.Path.GetFileName(path);
|
|
var r = CustomMessageBox.Show(
|
|
$"'{name}'\n\n이 항목을 휴지통으로 보내겠습니까?",
|
|
"AX Copilot — 삭제 확인",
|
|
MessageBoxButton.OKCancel,
|
|
MessageBoxImage.Warning);
|
|
|
|
if (r == MessageBoxResult.OK)
|
|
{
|
|
try
|
|
{
|
|
SendToRecycleBin(path);
|
|
_vm.ExitActionMode();
|
|
ShowToast("휴지통으로 이동됨", "\uE74D");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
CustomMessageBox.Show($"삭제 실패: {ex.Message}", "오류",
|
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_vm.ExitActionMode();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
case AxCopilot.ViewModels.FileAction.Rename:
|
|
{
|
|
var path = actionData.Path;
|
|
_vm.ExitActionMode();
|
|
_vm.InputText = $"rename {path}";
|
|
Dispatcher.BeginInvoke(() => { InputBox.CaretIndex = InputBox.Text.Length; },
|
|
System.Windows.Threading.DispatcherPriority.Input);
|
|
return true;
|
|
}
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
}
|