using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Markup; using System.Windows.Media; namespace AxCopilot.Views; public class HelpDetailWindow : Window, IComponentConnector { private enum TopMenu { Overview, Shortcuts, Prefixes } private const string CatAll = "전체"; private const string CatPopular = "⭐ 인기"; private static readonly (TopMenu Key, string Label, string Icon)[] TopMenus = new(TopMenu, string, string)[3] { (TopMenu.Overview, "개요", "\ue946"), (TopMenu.Shortcuts, "단축키 현황", "\ue765"), (TopMenu.Prefixes, "예약어 현황", "\ue8f4") }; private TopMenu _currentTopMenu = TopMenu.Overview; private readonly List _allItems; private readonly List _shortcutItems; private readonly List _prefixItems; private readonly List _overviewItems; private readonly string _globalHotkey; private List _categories = new List(); private int _currentPage; internal TextBlock SubtitleText; internal StackPanel TopMenuBar; internal TextBox SearchBox; internal WrapPanel CategoryBar; internal ItemsControl ItemsHost; internal Button PrevBtn; internal TextBlock PageIndicator; internal Button NextBtn; private bool _contentLoaded; private Brush ThemeAccent => (TryFindResource("AccentColor") as Brush) ?? ParseColor("#4B5EFC"); private Brush ThemePrimary => (TryFindResource("PrimaryText") as Brush) ?? Brushes.White; private Brush ThemeSecondary => (TryFindResource("SecondaryText") as Brush) ?? ParseColor("#8899CC"); public HelpDetailWindow(IEnumerable items, int totalCount, string globalHotkey = "Alt+Space") { InitializeComponent(); _allItems = items.ToList(); _globalHotkey = globalHotkey; _overviewItems = new List { new HelpItemModel { Category = "개요", Command = "AX Commander", Title = "키보드 하나로 모든 업무를 제어하는 AX Commander", Description = "단축키 한 번으로 앱 실행, 파일/폴더 검색, 계산, 클립보드 관리, 화면 캡처, 창 전환, 시스템 제어, 업무 일지, 루틴 자동화, AI 대화까지. 40개+ 명령어를 예약어로 즉시 접근.", Symbol = "\ue946", ColorBrush = ParseColor("#4B5EFC") }, new HelpItemModel { Category = "개요", Command = "사용법", Title = "예약어 + 키워드 → Enter", Description = "특수 문자를 맨 앞에 입력하면 해당 기능 모드로 전환됩니다. 예) = 수식, # 클립보드, ? 웹검색, ! AI 대화, cap 캡처. 예약어 없이 입력하면 앱/파일/폴더 검색.", Symbol = "\ue765", ColorBrush = ParseColor("#0078D4") }, new HelpItemModel { Category = "개요", Command = "데이터 보호", Title = "모든 데이터는 내 PC에만 안전하게 저장", Description = "설정, 클립보드, 대화 내역, 통계, 로그 등 모든 데이터가 로컬에 암호화 저장됩니다. 다른 PC에서는 열 수 없으며, 보존 기간 만료 시 자동 삭제됩니다.", Symbol = "\ue8b7", ColorBrush = ParseColor("#107C10") }, new HelpItemModel { Category = "AI", Command = "! (AX Agent)", Title = "AX Agent — AI 어시스턴트와 대화", Description = "AX Commander에서 ! 를 입력하면 AI 대화가 열립니다. 질문을 바로 물어보거나, 이전 대화를 이어갈 수 있습니다. 대화 주제별 분류, 검색, 사이드바 토글을 지원합니다.", Example = "! 오늘 회의 요약해줘\n! 이메일 초안 작성해줘", Symbol = "\ue8bd", ColorBrush = ParseColor("#8B2FC9") }, new HelpItemModel { Category = "AI", Command = "3탭 구조", Title = "Chat · Cowork · Code — 용도별 3탭 구조", Description = "Chat: 자유로운 AI 대화 — 질문, 번역, 요약, 아이디어 브레인스토밍.\nCowork: 업무 보조 — 파일 읽기/쓰기, 문서 생성(Excel·Word·PPT·HTML), 데이터 분석, 보고서 작성.\nCode: 코딩 도우미 — 개발, 리팩터링, 코드 리뷰, 보안 점검, 테스트 작성. 개발 환경 자동 감지.", Symbol = "\ue71b", ColorBrush = ParseColor("#3B82F6") }, new HelpItemModel { Category = "AI", Command = "AI 서비스", Title = "사내 AI · 외부 AI 서비스 선택 가능", Description = "관리자가 설정한 AI 서비스에 자동 연결됩니다. 사내 서버와 외부 서비스 중 선택할 수 있으며, 연결 정보는 암호화되어 보호됩니다.", Symbol = "\ue968", ColorBrush = ParseColor("#0078D4") }, new HelpItemModel { Category = "AI", Command = "실시간 응답", Title = "AI 응답이 실시간으로 표시", Description = "AI의 응답이 생성되는 즉시 화면에 표시됩니다. 긴 답변도 기다리지 않고 바로 읽기 시작할 수 있습니다.", Symbol = "\ue8ab", ColorBrush = ParseColor("#107C10") }, new HelpItemModel { Category = "AI", Command = "대화 보호", Title = "모든 대화 내역이 암호화 저장", Description = "대화 내역은 내 PC에서만 열람할 수 있도록 암호화됩니다. 다른 PC로 복사해도 열 수 없으며, 보존 기간 만료 시 자동 삭제됩니다.", Symbol = "\ue72e", ColorBrush = ParseColor("#C50F1F") }, new HelpItemModel { Category = "AI", Command = "AI 규칙 설정", Title = "관리자가 설정한 응답 규칙이 자동 적용", Description = "관리자가 지정한 역할, 응답 톤, 업무 규칙이 모든 대화에 자동 적용됩니다. AI의 응답 스타일을 일괄 관리할 수 있습니다.", Symbol = "\ue771", ColorBrush = ParseColor("#D97706") }, new HelpItemModel { Category = "AI", Command = "대화 관리", Title = "분류 · 검색 · 타임라인", Description = "대화를 주제별로 분류하고, 오늘/이전 타임라인으로 구분합니다. 검색과 카테고리 필터로 빠르게 찾을 수 있습니다.", Symbol = "\ue8f1", ColorBrush = ParseColor("#4B5EFC") }, new HelpItemModel { Category = "업무 보조", Command = "note", Title = "빠른 메모 저장 · 검색", Description = "note 뒤에 내용을 입력하면 즉시 메모가 저장됩니다. 나중에 note 키워드로 검색하면 이전 메모를 다시 찾을 수 있습니다. 간단한 아이디어나 할 일을 빠르게 기록하세요.", Example = "note 내일 보고서 마감\nnote 김부장님 연락처 확인", Symbol = "\ue70b", ColorBrush = ParseColor("#D97706") }, new HelpItemModel { Category = "업무 보조", Command = "journal", Title = "업무 일지 작성", Description = "journal 뒤에 내용을 입력하면 날짜별 업무 일지로 자동 기록됩니다. 하루 동안의 업무 내용을 간결하게 쌓아가면 주간 보고나 회고에 활용할 수 있습니다.", Example = "journal 배포 완료\njournal 클라이언트 미팅 30분", Symbol = "\ue8f2", ColorBrush = ParseColor("#0078D4") }, new HelpItemModel { Category = "업무 보조", Command = "pipe", Title = "클립보드 텍스트 파이프라인 변환", Description = "클립보드에 복사된 텍스트를 여러 변환 함수로 한 번에 처리합니다. upper(대문자), lower(소문자), trim(공백 제거), wrap(줄바꿈), sort(정렬) 등을 연결할 수 있습니다.", Example = "pipe upper | trim | wrap 80", Symbol = "\ue8ab", ColorBrush = ParseColor("#107C10") }, new HelpItemModel { Category = "업무 보조", Command = "diff", Title = "두 텍스트 비교 (Diff)", Description = "클립보드의 두 텍스트를 비교하여 차이점을 한눈에 보여줍니다. 코드 변경 사항 확인, 문서 버전 비교 등에 유용합니다.", Example = "diff", Symbol = "\ue8fd", ColorBrush = ParseColor("#6B2C91") }, new HelpItemModel { Category = "업무 보조", Command = "encode", Title = "인코딩 · 디코딩 변환", Description = "Base64, URL, HTML, Unicode 등 다양한 형식으로 텍스트를 인코딩하거나 디코딩합니다. 개발자에게 특히 유용한 변환 도구입니다.", Example = "encode base64 hello\nencode url 한글 테스트", Symbol = "\ue943", ColorBrush = ParseColor("#323130") }, new HelpItemModel { Category = "업무 보조", Command = "routine", Title = "반복 작업 루틴 자동화", Description = "자주 하는 작업 묶음을 루틴으로 등록해 두면 한 번의 명령으로 여러 앱을 동시에 열거나 작업 환경을 구성할 수 있습니다. 출근·퇴근 루틴 등을 만들어 보세요.", Example = "routine start 출근\nroutine list", Symbol = "\ue8f5", ColorBrush = ParseColor("#BE185D") }, new HelpItemModel { Category = "업무 보조", Command = "stats", Title = "텍스트 통계 (글자수·단어수·줄수)", Description = "클립보드에 복사된 텍스트의 글자 수, 단어 수, 줄 수를 즉시 계산합니다. 보고서 분량 체크, SNS 글자 수 제한 확인 등에 활용하세요.", Example = "stats", Symbol = "\ue9d9", ColorBrush = ParseColor("#44546A") }, new HelpItemModel { Category = "업무 보조", Command = "json", Title = "JSON 파싱 · 정리 · 미리보기", Description = "클립보드에 복사된 JSON을 자동으로 파싱하고 읽기 좋은 형태로 정리합니다. 들여쓰기, 키 하이라이트, 복사 기능을 제공합니다.", Example = "json {\"key\":\"value\"}", Symbol = "\ue8a5", ColorBrush = ParseColor("#4B5EFC") } }; _shortcutItems = BuildShortcutItems(_globalHotkey); _prefixItems = _allItems.ToList(); SubtitleText.Text = $"총 {totalCount}개 명령어 · 단축키 {_shortcutItems.Count}개 · 예약어 {_prefixItems.Count}개"; BuildTopMenu(); SwitchTopMenu(TopMenu.Overview); base.KeyDown += OnKeyDown; } private static List BuildShortcutItems(string globalHotkey = "Alt+Space") { List list = new List(); string key = globalHotkey.Replace("+", " + "); list.Add(MakeShortcut("전역", key, "AX Commander 열기/닫기", "어느 창에서든 눌러 AX Commander를 즉시 호출하거나 닫습니다. 설정 › 일반에서 원하는 키 조합으로 변경할 수 있습니다.", "\ue765", "#4B5EFC")); list.Add(MakeShortcut("전역", "PrintScreen", "화면 캡처 즉시 실행", "AX Commander를 열지 않고 곧바로 캡처를 시작합니다. 설정 › 캡처 탭에서 '글로벌 단축키 활성화'를 켜야 동작합니다.", "\ue722", "#BE185D")); list.Add(MakeShortcut("AX Commander 탐색", "Escape", "창 닫기 / 이전 단계로", "액션 모드(→ 로 진입)에 있을 때는 일반 검색 화면으로 돌아갑니다. 일반 화면이면 AX Commander를 숨깁니다.", "\ue711", "#999999")); list.Add(MakeShortcut("AX Commander 탐색", "Enter", "선택 항목 실행", "파일·앱이면 열기, URL이면 브라우저 열기, 시스템 명령이면 즉시 실행, 계산기 결과면 클립보드에 복사합니다.", "\ue768", "#107C10")); list.Add(MakeShortcut("AX Commander 탐색", "Shift + Enter", "대형 텍스트(Large Type) 표시 / 클립보드 병합 실행", "선택된 텍스트·검색어를 화면 전체에 크게 띄웁니다. 클립보드 병합 항목이 있을 때는 선택한 항목들을 줄바꿈으로 합쳐 클립보드에 복사합니다.", "\ue8c1", "#8764B8")); list.Add(MakeShortcut("AX Commander 탐색", "↑ / ↓", "결과 목록 위/아래 이동", "목록 끝에서 계속 누르면 처음/끝으로 순환합니다.", "\ue74a", "#0078D4")); list.Add(MakeShortcut("AX Commander 탐색", "PageUp / PageDown", "목록 5칸 빠른 이동", "한 번에 5항목씩 건너뜁니다. 빠른 목록 탐색에 유용합니다.", "\ue74a", "#0078D4")); list.Add(MakeShortcut("AX Commander 탐색", "Home / End", "목록 처음 / 마지막 항목으로 점프", "입력창 커서가 맨 앞(또는 입력이 없을 때)이면 첫 항목으로, 맨 끝이면 마지막 항목으로 선택이 이동합니다.", "\ue74a", "#0078D4")); list.Add(MakeShortcut("AX Commander 탐색", "→ (오른쪽 화살표)", "액션 모드 진입", "파일·앱 항목을 선택한 상태에서 → 를 누르면 경로 복사, 탐색기 열기, 관리자 실행, 터미널, 속성, 이름 변경, 삭제 메뉴가 나타납니다.", "\ue76c", "#44546A")); list.Add(MakeShortcut("AX Commander 탐색", "Tab", "선택 항목 제목으로 자동완성", "현재 선택된 항목의 이름을 입력창에 채웁니다. 이후 계속 타이핑하거나 Enter로 실행합니다.", "\ue748", "#006EAF")); list.Add(MakeShortcut("AX Commander 탐색", "Shift + ↑/↓", "클립보드 병합 선택", "클립보드 히스토리(# 모드) 에서 여러 항목을 이동하면서 선택/해제합니다. Shift+Enter로 선택한 항목들을 한 번에 붙여넣을 수 있습니다.", "\ue8c1", "#B7791F")); list.Add(MakeShortcut("런처 기능", "F1", "도움말 창 열기", "이 화면을 직접 엽니다. 'help' 를 입력하는 것과 동일합니다.", "\ue897", "#6B7280")); list.Add(MakeShortcut("런처 기능", "F2", "선택 파일 이름 변경", "파일·폴더 항목을 선택한 상태에서 누르면 rename [경로] 형태로 입력창에 채워지고 이름 변경 핸들러가 실행됩니다.", "\ue70f", "#6B2C91")); list.Add(MakeShortcut("런처 기능", "F5", "파일 인덱스 즉시 재구축", "백그라운드에서 파일·앱 인덱싱을 다시 실행합니다. 새 파일을 추가했거나 목록이 오래됐을 때 사용합니다.", "\ue72c", "#059669")); list.Add(MakeShortcut("런처 기능", "Delete", "최근 실행 목록에서 항목 제거", "recent 목록에 있는 항목을 제거합니다. 확인 다이얼로그가 표시되며 OK를 눌러야 실제로 제거됩니다.", "\ue74d", "#DC2626")); list.Add(MakeShortcut("런처 기능", "Ctrl + ,", "설정 창 열기", "AX Copilot 설정 창을 엽니다. 런처가 자동으로 숨겨집니다.", "\ue713", "#44546A")); list.Add(MakeShortcut("런처 기능", "Ctrl + L", "입력창 전체 초기화", "현재 입력된 검색어·예약어를 모두 지우고 커서를 빈 입력창으로 돌립니다.", "\ue894", "#4B5EFC")); list.Add(MakeShortcut("런처 기능", "Ctrl + C", "선택 항목 파일 이름 복사", "파일·앱 항목이 선택된 경우 확장자를 제외한 파일 이름을 클립보드에 복사하고 토스트로 알립니다.", "\ue8c8", "#8764B8")); list.Add(MakeShortcut("런처 기능", "Ctrl + Shift + C", "선택 항목 전체 경로 복사", "선택된 파일·폴더의 절대 경로(예: C:\\Users\\...)를 클립보드에 복사합니다.", "\ue8c8", "#C55A11")); list.Add(MakeShortcut("런처 기능", "Ctrl + Shift + E", "파일 탐색기에서 선택 항목 열기", "Windows 탐색기가 열리고 해당 파일·폴더가 하이라이트 선택된 상태로 표시됩니다.", "\ue838", "#107C10")); list.Add(MakeShortcut("런처 기능", "Ctrl + Enter", "관리자(UAC) 권한으로 실행", "선택된 파일·앱을 UAC 권한 상승 후 실행합니다. 설치 프로그램이나 시스템 설정 앱에 유용합니다.", "\ue7ef", "#C50F1F")); list.Add(MakeShortcut("런처 기능", "Alt + Enter", "파일 속성 대화 상자 열기", "Windows의 '파일 속성' 창(크기·날짜·권한 등)을 엽니다.", "\ue946", "#6B2C91")); list.Add(MakeShortcut("런처 기능", "Ctrl + T", "선택 항목 위치에서 터미널 열기", "선택된 파일이면 해당 폴더에서, 폴더이면 그 경로에서 Windows Terminal(wt.exe)이 열립니다. wt가 없으면 cmd로 대체됩니다.", "\ue756", "#323130")); list.Add(MakeShortcut("런처 기능", "Ctrl + P", "즐겨찾기 즉시 추가 / 제거 (핀)", "파일·폴더 항목을 선택한 상태에서 누르면 favorites.json 에 추가하거나 이미 있으면 제거합니다. 토스트로 결과를 알립니다.", "\ue734", "#D97706")); list.Add(MakeShortcut("런처 기능", "Ctrl + B", "즐겨찾기 목록 보기 / 닫기 토글", "입력창이 'fav' 이면 초기화하고, 아니면 'fav' 를 입력해 즐겨찾기 목록을 표시합니다.", "\ue735", "#D97706")); list.Add(MakeShortcut("런처 기능", "Ctrl + R", "최근 실행 목록 보기 / 닫기 토글", "'recent' 를 입력해 최근 실행 항목을 표시합니다.", "\ue81c", "#0078D4")); list.Add(MakeShortcut("런처 기능", "Ctrl + H", "클립보드 히스토리 목록 열기", "'#' 를 입력해 클립보드에 저장된 최근 복사 항목 목록을 표시합니다.", "\ue77f", "#8B2FC9")); list.Add(MakeShortcut("런처 기능", "Ctrl + D", "다운로드 폴더 바로가기", "사용자 홈의 Downloads 폴더 경로를 입력창에 채워 탐색기로 열 수 있게 합니다.", "\ue8b7", "#107C10")); list.Add(MakeShortcut("런처 기능", "Ctrl + F", "파일 검색 모드로 전환", "입력창을 초기화하고 포커스를 이동합니다. 이후 파일명을 바로 타이핑해 검색할 수 있습니다.", "\ue71e", "#4B5EFC")); list.Add(MakeShortcut("런처 기능", "Ctrl + W", "런처 창 즉시 닫기", "현재 입력 내용에 관계없이 런처를 즉시 숨깁니다.", "\ue711", "#9999BB")); list.Add(MakeShortcut("런처 기능", "Ctrl + K", "단축키 참조 모달 창 열기", "모든 단축키와 설명을 보여주는 별도 모달 창이 열립니다. Esc 또는 닫기 버튼으로 닫습니다.", "\ue8fd", "#4B5EFC")); list.Add(MakeShortcut("런처 기능", "Ctrl + 1 ~ 9", "N번째 결과 항목 바로 실행", "목록에 번호 배지(1~9)가 표시된 항목을 해당 숫자 키로 즉시 실행합니다. 마우스 없이 빠른 실행에 유용합니다.", "\ue8c4", "#107C10")); list.Add(MakeShortcut("기타 창", "← / →", "헬프 창 카테고리 이동", "이 도움말 창에서 하위 카테고리 탭을 왼쪽/오른쪽으로 이동합니다.", "\ue76b", "#4455AA")); list.Add(MakeShortcut("기타 창", "1 / 2 / 3", "헬프 창 상단 메뉴 전환", "이 도움말 창에서 개요(1), 단축키 현황(2), 예약어 현황(3)을 키보드로 전환합니다.", "\ue8bd", "#4455AA")); list.Add(MakeShortcut("기타 창", "방향키 (캡처 중)", "영역 선택 경계 1px 미세 조정", "화면 캡처의 영역 선택 모드에서 선택 영역 경계를 1픽셀씩 정밀 조정합니다.", "\ue745", "#BE185D")); list.Add(MakeShortcut("기타 창", "Shift + 방향키 (캡처 중)", "영역 선택 경계 10px 이동", "화면 캡처의 영역 선택 모드에서 선택 영역 경계를 10픽셀씩 빠르게 이동합니다.", "\ue745", "#BE185D")); return list; } private static SolidColorBrush ParseColor(string hex) { try { return new SolidColorBrush((Color)ColorConverter.ConvertFromString(hex)); } catch { return new SolidColorBrush(Colors.Gray); } } private static HelpItemModel MakeShortcut(string cat, string key, string title, string desc, string symbol, string color) { return new HelpItemModel { Category = cat, Command = key, Title = title, Description = desc, Symbol = symbol, ColorBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(color)) }; } private void BuildTopMenu() { TopMenuBar.Children.Clear(); (TopMenu, string, string)[] topMenus = TopMenus; for (int i = 0; i < topMenus.Length; i++) { (TopMenu, string, string) tuple = topMenus[i]; TopMenu item = tuple.Item1; string item2 = tuple.Item2; string item3 = tuple.Item3; TopMenu k = item; StackPanel stackPanel = new StackPanel { Orientation = Orientation.Horizontal }; stackPanel.Children.Add(new TextBlock { Text = item3, FontFamily = new FontFamily("Segoe MDL2 Assets"), FontSize = 14.0, Foreground = ThemeAccent, VerticalAlignment = VerticalAlignment.Center, Margin = new Thickness(0.0, 0.0, 6.0, 0.0) }); stackPanel.Children.Add(new TextBlock { Text = item2, FontSize = 12.0, VerticalAlignment = VerticalAlignment.Center }); Button button = new Button { Content = stackPanel, FontWeight = FontWeights.SemiBold, Padding = new Thickness(16.0, 8.0, 16.0, 8.0), Margin = new Thickness(4.0, 0.0, 4.0, 0.0), Cursor = Cursors.Hand, Background = Brushes.Transparent, Foreground = ThemeSecondary, BorderThickness = new Thickness(0.0, 0.0, 0.0, 2.0), BorderBrush = Brushes.Transparent, Tag = k }; button.Click += delegate { SwitchTopMenu(k); }; TopMenuBar.Children.Add(button); } } private void SwitchTopMenu(TopMenu menu) { _currentTopMenu = menu; foreach (object child in TopMenuBar.Children) { if (!(child is Button { Tag: var tag } button)) { continue; } bool flag = tag is TopMenu topMenu && topMenu == menu; button.BorderBrush = (flag ? ThemeAccent : Brushes.Transparent); button.Foreground = (flag ? ThemePrimary : ThemeSecondary); if (!(button.Content is StackPanel stackPanel)) { continue; } foreach (object child2 in stackPanel.Children) { if (child2 is TextBlock textBlock && textBlock.FontFamily.Source != "Segoe MDL2 Assets") { textBlock.Foreground = button.Foreground; } } } switch (menu) { case TopMenu.Overview: BuildCategoryBarFor(_overviewItems); break; case TopMenu.Shortcuts: BuildCategoryBarFor(_shortcutItems); break; case TopMenu.Prefixes: BuildCategoryBarFor(_prefixItems); break; } } private void BuildCategoryBarFor(List sourceItems) { HashSet hashSet = new HashSet(); _categories = new List { "전체" }; if (_currentTopMenu == TopMenu.Prefixes) { _categories.Add("⭐ 인기"); } foreach (HelpItemModel sourceItem in sourceItems) { if (hashSet.Add(sourceItem.Category)) { _categories.Add(sourceItem.Category); } } BuildCategoryBar(); NavigateToPage(0); } private void BuildCategoryBar() { CategoryBar.Children.Clear(); for (int i = 0; i < _categories.Count; i++) { string content = _categories[i]; int idx = i; Button button = new Button { Content = content, FontSize = 10.5, FontWeight = FontWeights.SemiBold, Padding = new Thickness(9.0, 4.0, 9.0, 4.0), Margin = new Thickness(0.0, 0.0, 3.0, 0.0), Cursor = Cursors.Hand, Background = Brushes.Transparent, Foreground = ThemeSecondary, BorderThickness = new Thickness(0.0), Tag = idx }; button.Click += delegate { NavigateToPage(idx); }; CategoryBar.Children.Add(button); } } private List GetCurrentSourceItems() { TopMenu currentTopMenu = _currentTopMenu; if (1 == 0) { } List result = currentTopMenu switch { TopMenu.Overview => _overviewItems, TopMenu.Shortcuts => _shortcutItems, TopMenu.Prefixes => _prefixItems, _ => _overviewItems, }; if (1 == 0) { } return result; } private void NavigateToPage(int pageIndex) { if (_categories.Count == 0) { return; } _currentPage = Math.Clamp(pageIndex, 0, _categories.Count - 1); List currentSourceItems = GetCurrentSourceItems(); string cat = _categories[_currentPage]; List list; if (cat == "전체") { list = currentSourceItems; } else if (cat == "⭐ 인기") { HashSet popularCmds = new HashSet(StringComparer.OrdinalIgnoreCase) { "파일/폴더", "?", "#", "!", "clip", "pipe", "diff", "win" }; list = currentSourceItems.Where((HelpItemModel i) => popularCmds.Contains(i.Command) || i.Command.StartsWith("?") || i.Title.Contains("검색") || i.Title.Contains("클립보드") || (i.Title.Contains("파일") && i.Category != "키보드")).ToList(); } else { list = currentSourceItems.Where((HelpItemModel i) => i.Category == cat).ToList(); } ItemsHost.ItemsSource = list; for (int num = 0; num < CategoryBar.Children.Count; num++) { if (CategoryBar.Children[num] is Button button) { if (num == _currentPage) { button.Background = ThemeAccent; button.Foreground = Brushes.White; } else { button.Background = Brushes.Transparent; button.Foreground = ThemeSecondary; } } } PageIndicator.Text = $"{cat} ({list.Count}개)"; PrevBtn.Visibility = ((_currentPage <= 0) ? Visibility.Hidden : Visibility.Visible); NextBtn.Visibility = ((_currentPage >= _categories.Count - 1) ? Visibility.Hidden : Visibility.Visible); } private void OnKeyDown(object sender, KeyEventArgs e) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected I4, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 Key key = e.Key; Key val = key; if ((int)val <= 23) { if ((int)val != 13) { if ((int)val == 23) { if (_currentPage > 0) { NavigateToPage(_currentPage - 1); } e.Handled = true; } } else { Close(); } } else if ((int)val != 25) { switch (val - 35) { case 0: SwitchTopMenu(TopMenu.Overview); e.Handled = true; break; case 1: SwitchTopMenu(TopMenu.Shortcuts); e.Handled = true; break; case 2: SwitchTopMenu(TopMenu.Prefixes); e.Handled = true; break; } } else { if (_currentPage < _categories.Count - 1) { NavigateToPage(_currentPage + 1); } e.Handled = true; } } private void Prev_Click(object sender, RoutedEventArgs e) { NavigateToPage(_currentPage - 1); } private void Next_Click(object sender, RoutedEventArgs e) { NavigateToPage(_currentPage + 1); } private void Close_Click(object sender, RoutedEventArgs e) { Close(); } private void SearchBox_TextChanged(object sender, TextChangedEventArgs e) { string query = SearchBox.Text.Trim(); if (string.IsNullOrEmpty(query)) { NavigateToPage(_currentPage); return; } List currentSourceItems = GetCurrentSourceItems(); List list = currentSourceItems.Where((HelpItemModel i) => i.Title.Contains(query, StringComparison.OrdinalIgnoreCase) || i.Command.Contains(query, StringComparison.OrdinalIgnoreCase) || i.Description.Contains(query, StringComparison.OrdinalIgnoreCase) || i.Category.Contains(query, StringComparison.OrdinalIgnoreCase)).ToList(); ItemsHost.ItemsSource = list; PageIndicator.Text = $"검색: \"{query}\" ({list.Count}개)"; } private void Window_MouseDown(object sender, MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Left && e.LeftButton == MouseButtonState.Pressed) { try { DragMove(); } catch { } } } private void Window_KeyDown(object sender, KeyEventArgs e) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 if ((int)e.Key == 13) { Close(); } } [DebuggerNonUserCode] [GeneratedCode("PresentationBuildTasks", "10.0.5.0")] public void InitializeComponent() { if (!_contentLoaded) { _contentLoaded = true; Uri resourceLocator = new Uri("/AxCopilot;component/views/helpdetailwindow.xaml", UriKind.Relative); Application.LoadComponent(this, resourceLocator); } } [DebuggerNonUserCode] [GeneratedCode("PresentationBuildTasks", "10.0.5.0")] [EditorBrowsable(EditorBrowsableState.Never)] void IComponentConnector.Connect(int connectionId, object target) { switch (connectionId) { case 1: ((HelpDetailWindow)target).MouseDown += Window_MouseDown; ((HelpDetailWindow)target).KeyDown += Window_KeyDown; break; case 2: SubtitleText = (TextBlock)target; break; case 3: ((Button)target).Click += Close_Click; break; case 4: TopMenuBar = (StackPanel)target; break; case 5: SearchBox = (TextBox)target; SearchBox.TextChanged += SearchBox_TextChanged; break; case 6: CategoryBar = (WrapPanel)target; break; case 7: ItemsHost = (ItemsControl)target; break; case 8: PrevBtn = (Button)target; PrevBtn.Click += Prev_Click; break; case 9: PageIndicator = (TextBlock)target; break; case 10: NextBtn = (Button)target; NextBtn.Click += Next_Click; break; default: _contentLoaded = true; break; } } }