飞扬 / 极光便签 公开
main
极光便签/MainWindow.xaml.cs
MainWindow.xaml.cs11.4 KB
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Threading.Tasks;
using System.Windows.Threading;
using System.Diagnostics;
using System.Threading;

namespace MyCoolApp
{
    public partial class MainWindow : Window
    {
        // --- 变量定义 ---
        private string filePath, configPath, lastClipText = "", searchEngineUrl = "https://www.bing.com/search?q=";
        private int skinIndex = 0, timeLeftSeconds = 0;
        private bool preferEdge = true;
        private uint currentVK = 0x51; // 默认 Q
        private DispatcherTimer countdownTimer, memTimer;
        private const int HOTKEY_ID = 9001;

        // --- Win32 API 导入 ---
        [DllImport("user32.dll")] private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
        [DllImport("user32.dll")] private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
        [DllImport("user32.dll")] private static extern bool AddClipboardFormatListener(IntPtr hwnd);
        [DllImport("psapi.dll")] private static extern bool EmptyWorkingSet(IntPtr hProcess);

        // 定义一个全局唯一的 Mutex 变量
        private static Mutex mutex = null;

        public MainWindow()
        {
            // 检查是否已有实例在运行
            bool isNewInstance;
            mutex = new Mutex(true, "Global\\AuroraNote_Unique_Mutex_ID", out isNewInstance);

            if (!isNewInstance)
            {
                // 如果不是新实例,直接关闭当前进程
                MessageBox.Show("极光便签 已经在运行中。");
                Application.Current.Shutdown();
                return;
            }

            InitializeComponent();

            // --- 固定文件名,不再使用随机 ID ---
            // 这样重启后永远能读到上一次的笔记
            filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Notes.txt");
            configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Settings.ini");

            LoadConfig();
            LoadNote();

            // 内存优化定时器
            memTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(30) };
            memTimer.Tick += (s, e) => ReduceMemory();
            memTimer.Start();
        }

        // --- 核心优化:内存压缩 ---
        private void ReduceMemory()
        {
            try
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                    EmptyWorkingSet(Process.GetCurrentProcess().Handle);
            }
            catch { }
        }

        // --- 智能搜索逻辑 (F1) ---
        private void SmartSearch(string query)
        {
            if (string.IsNullOrWhiteSpace(query)) return;
            string url = query.StartsWith("http") ? query : searchEngineUrl + Uri.EscapeDataString(query);
            try
            {
                string browser = preferEdge ? "msedge.exe" : "chrome.exe";
                try { Process.Start(new ProcessStartInfo(browser, url) { UseShellExecute = true }); }
                catch { Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }); }
            }
            catch { }
        }

        private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.F1) { SmartSearch(txtNote.SelectedText); e.Handled = true; }
        }

        // --- 系统热键与剪贴板处理 ---
        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);
            IntPtr handle = new WindowInteropHelper(this).Handle;
            HwndSource.FromHwnd(handle).AddHook(HwndHook);
            AddClipboardFormatListener(handle);
            RegisterHotKey(handle, HOTKEY_ID, 0x0002 | 0x0004, currentVK); // Ctrl+Shift+Key
        }

        private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == 0x0312 && wParam.ToInt32() == HOTKEY_ID)
            {
                if (this.Visibility == Visibility.Visible) { this.Hide(); ReduceMemory(); }
                else { this.Show(); this.Activate(); }
            }
            if (msg == 0x031D) OnClipboardChanged();
            return IntPtr.Zero;
        }

        private async void OnClipboardChanged()
        {
            try
            {
                await Task.Delay(300); // 避开系统占用
                if (Clipboard.ContainsText())
                {
                    string txt = Clipboard.GetText();

                    // --- 新增逻辑:防止自循环 ---
                    // 如果剪贴板的内容 等于 文本框当前选中的文字,说明是你自己在便签里点的复制
                    // 我们需要检查 txtNote 是否被初始化,并且判断内容是否重复
                    bool isInternalCopy = false;
                    Application.Current.Dispatcher.Invoke(() => {
                        if (txtNote.SelectedText == txt)
                        {
                            isInternalCopy = true;
                        }
                    });

                    if (isInternalCopy) return; // 如果是内部复制,直接退出,不记录
                                                // -----------------------

                    if (!string.IsNullOrWhiteSpace(txt) && txt != lastClipText)
                    {
                        lastClipText = txt;
                        txtNote.AppendText($"\n--- 采集 {DateTime.Now:HH:mm} ---\n{txt}\n");
                        txtNote.ScrollToEnd();
                    }
                }
            }
            catch { }
        }

        // --- 在 MainWindow 类中添加此方法 ---
        private void About_Click(object sender, RoutedEventArgs e)
        {
            string version = "v1.0.0";
            string author = "小野"; // 这里换成你的名字或代号
            string info = $"【极光便签】\n\n" +
                          $"版本:{version}\n" +
                          $"作者:{author}\n\n" +
                          $"LB5.NET\n\n" +
                          $"功能特性:\n" +
                          $"• 内存极致压缩技术\n" +
                          $"• 自定义老板键与搜索平台\n" +
                          $"• 智能剪贴板自动化采集\n\n" +
                          $"感谢使用!";

            MessageBox.Show(info, "关于", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        // --- 番茄钟逻辑 ---
        private void BtnStartTimer_Click(object sender, RoutedEventArgs e)
        {
            if (int.TryParse(txtTimerMin.Text, out int mins))
            {
                if (countdownTimer != null) countdownTimer.Stop();
                timeLeftSeconds = mins * 60;
                lblTimer.Text = $"{mins:D2}:00";
                lblTimer.Visibility = Visibility.Visible;
                mainBorder.BorderBrush = Brushes.Crimson;
                countdownTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
                countdownTimer.Tick += (s, ev) => {
                    if (timeLeftSeconds > 0)
                    {
                        timeLeftSeconds--;
                        lblTimer.Text = $"{timeLeftSeconds / 60:D2}:{timeLeftSeconds % 60:D2}";
                    }
                    else
                    {
                        ((DispatcherTimer)s).Stop();
                        mainBorder.BorderBrush = Brushes.Gold;
                        lblTimer.Visibility = Visibility.Collapsed;
                        this.Show(); this.Activate();
                        MessageBox.Show("专注时间到!");
                    }
                };
                countdownTimer.Start();
            }
        }

        // --- 设置保存与读取 ---
        private void SetSearchEngine_Click(object sender, RoutedEventArgs e)
        {
            searchEngineUrl = (sender as MenuItem).Tag.ToString();
            UpdateMenuCheck(); SaveConfig();
        }

        private void SetBrowser_Click(object sender, RoutedEventArgs e)
        {
            preferEdge = (sender == menuEdge);
            UpdateMenuCheck(); SaveConfig();
        }

        private void SetHotkey_Click(object sender, RoutedEventArgs e)
        {
            currentVK = (uint)KeyInterop.VirtualKeyFromKey((Key)Enum.Parse(typeof(Key), (sender as MenuItem).Tag.ToString()));
            SaveConfig(); MessageBox.Show("老板键已更改,重启后生效。");
        }

        private void UpdateMenuCheck()
        {
            menuBing.IsChecked = searchEngineUrl.Contains("bing");
            menuBaidu.IsChecked = searchEngineUrl.Contains("baidu");
            menuGoogle.IsChecked = searchEngineUrl.Contains("google");
            menuSogou.IsChecked = searchEngineUrl.Contains("sogou");
            menuEdge.IsChecked = preferEdge; menuChrome.IsChecked = !preferEdge;
        }

        private void SaveConfig() => File.WriteAllText(configPath, $"{currentVK}|{preferEdge}|{searchEngineUrl}");
        private void LoadConfig()
        {
            if (File.Exists(configPath))
            {
                try
                {
                    var p = File.ReadAllText(configPath).Split('|');
                    if (p.Length >= 3) { currentVK = uint.Parse(p[0]); preferEdge = bool.Parse(p[1]); searchEngineUrl = p[2]; }
                }
                catch { }
            }
            UpdateMenuCheck();
        }

        // --- 基础交互逻辑 ---
        private void Window_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (Keyboard.Modifiers == ModifierKeys.Control)
            {
                this.Opacity = e.Delta > 0 ? Math.Min(1.0, this.Opacity + 0.1) : Math.Max(0.2, this.Opacity - 0.1);
                e.Handled = true;
            }
        }
        private void BtnSkin_Click(object sender, RoutedEventArgs e)
        {
            string[] c = { "#DD222222", "#DD1E3A5F", "#DD2D5A27", "#DD4B0082" };
            skinIndex = (skinIndex + 1) % c.Length;
            mainBorder.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString(c[skinIndex]));
        }
        private void BtnPin_Click(object sender, RoutedEventArgs e) { this.Topmost = !this.Topmost; btnPin.Foreground = this.Topmost ? Brushes.Cyan : Brushes.Gray; }
        private void BtnClose_Click(object sender, RoutedEventArgs e) => this.Close();
        private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (e.LeftButton == MouseButtonState.Pressed) this.DragMove(); }
        private void ClearAll_Click(object sender, RoutedEventArgs e) => txtNote.Clear();
        private void BtnSearch_Click(object sender, RoutedEventArgs e) => SmartSearch(txtNote.SelectedText);
        private void LoadNote() { if (File.Exists(filePath)) txtNote.Text = File.ReadAllText(filePath); }
        private void txtNote_TextChanged(object sender, TextChangedEventArgs e) { try { File.WriteAllText(filePath, txtNote.Text); } catch { } }
    }
}