├── .gitattributes ├── .gitignore ├── HtKit ├── AppPath.cs ├── AutoStart.cs ├── ChooseFileManager.cs ├── Debug.cs ├── Dispatch.cs ├── Downloader │ ├── DownloadConfig.cs │ ├── DownloadEventArgs.cs │ ├── DownloadService.cs │ └── Downloader.cs ├── Extension │ ├── DateExtension.cs │ ├── ImageExtension.cs │ ├── IntExtension.cs │ ├── ListExtension.cs │ └── StringExtension.cs ├── FileHelper.cs ├── HtColor.cs ├── HtKit.csproj ├── HtZipHelper.cs ├── MemoryHelper.cs ├── NetWorking │ └── NetHelper.cs ├── QuickShort.cs └── Win32Api.cs ├── LICENSE ├── MMClipboard.Desktop ├── App.xaml ├── App.xaml.cs ├── AssemblyInfo.cs ├── CustomUI │ ├── Styles │ │ ├── UIButtonStyles.xaml │ │ ├── UIToggleButtonStyles.xaml │ │ └── UIToolTipStyles.xaml │ ├── UIButton.cs │ └── UIToggleButton.cs ├── Dictionary │ ├── StaticFonts.xaml │ ├── StaticSolidColors.xaml │ └── TaskbarResource.xaml ├── Font │ ├── JetBrainsMono-Light.ttf │ └── JetBrainsMono-Regular.ttf ├── Images │ ├── Add.png │ ├── AppMainPage.png │ ├── Calendar.png │ ├── Close1.png │ ├── Collected.png │ ├── DefaultBg.png │ ├── DirectoryDefaultLogo.png │ ├── Exe.png │ ├── FileDefaultLogo.png │ ├── FileIcons │ │ └── 文件夹.png │ ├── IconPng.png │ ├── ItemMenu.png │ ├── Logo.ico │ ├── Search.png │ ├── SettingImg.png │ ├── TaskbarIcon.ico │ ├── close.png │ ├── defaultImage.png │ ├── delete.png │ ├── edit.png │ └── noCollect.png ├── MMClipboard.csproj ├── MMClipboard.csproj.user ├── MMClipboard.sln ├── Model │ ├── ClipItemModel.cs │ └── ShortcutPhraseModel.cs ├── Properties │ └── PublishProfiles │ │ ├── FolderProfile.pubxml │ │ └── FolderProfile.pubxml.user ├── SharedInstance.cs ├── StartUp.cs ├── Style │ ├── CalendarStyle.xaml │ ├── CollectToggleButtonStyle.xaml │ ├── ContextMenuStyle.xaml │ ├── PageStyle.xaml │ ├── SearchTextBoxStyle.xaml │ └── TextBlockStyles.xaml ├── Tool │ ├── AppUpdate │ │ ├── AppUpdateManager.cs │ │ └── VersionModel.cs │ ├── BindingConverter │ │ ├── HistoryItemDataConverters.cs │ │ ├── NodataTipHideConverter.cs │ │ ├── PhraseItemDataConverters.cs │ │ └── SettingPageConverter.cs │ ├── CacheHelper.cs │ ├── ClipTypeEnum.cs │ ├── ClipboardListener.cs │ ├── CopyAndPasteHelper.cs │ ├── DataBaseController.cs │ ├── HotKeyManager.cs │ ├── OpenExternalWindowHelper.cs │ └── UIElementHelper.cs ├── UserConfigs │ ├── Config.cs │ └── UserConfig.cs ├── View │ ├── AppUpdateWindow.xaml │ ├── AppUpdateWindow.xaml.cs │ ├── ClipboardHistory.xaml │ ├── ClipboardHistory.xaml.cs │ ├── ContentInputWindow.xaml │ ├── ContentInputWindow.xaml.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── SearchWindow.xaml │ ├── SearchWindow.xaml.cs │ ├── SettingWindow.xaml │ ├── SettingWindow.xaml.cs │ ├── ShortcutPhraseWindow.xaml │ ├── ShortcutPhraseWindow.xaml.cs │ ├── SmallWindow.xaml │ └── SmallWindow.xaml.cs └── ViewModel │ ├── AppUpdateViewModel.cs │ ├── ClipboardHistoryViewModel.cs │ ├── MainViewModel.cs │ ├── SettingViewModel.cs │ ├── ShortcutPhraseViewModel.cs │ ├── TaskbarViewModel.cs │ └── WindowBackgroundModel.cs ├── MMClipboard.UpdateTool_Python ├── .idea │ ├── MMClipboard.UpdateTool_Python.iml │ ├── inspectionProfiles │ │ ├── Project_Default.xml │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ ├── vcs.xml │ └── workspace.xml ├── UpdateTool.py ├── UpdateTool.spec ├── build │ └── UpdateTool │ │ ├── Analysis-00.toc │ │ ├── EXE-00.toc │ │ ├── PKG-00.toc │ │ ├── PYZ-00.pyz │ │ ├── PYZ-00.toc │ │ ├── UpdateTool.pkg │ │ ├── base_library.zip │ │ ├── localpycs │ │ ├── pyimod01_archive.pyc │ │ ├── pyimod02_importers.pyc │ │ ├── pyimod03_ctypes.pyc │ │ ├── pyimod04_pywin32.pyc │ │ └── struct.pyc │ │ ├── warn-UpdateTool.txt │ │ └── xref-UpdateTool.html ├── ddd.ico └── dist │ └── UpdateTool.exe ├── MMClipboard.sln ├── README.md ├── VersionInfo.json └── doc ├── QRCode └── WeChat.jpg └── preview ├── MaxSnip.png ├── ShortcutSnip.png └── SmallSnip.png /.gitattributes: -------------------------------------------------------------------------------- 1 | *.cs linguist-language=C# 2 | *.xaml linguist-language=C# 3 | *.html linguist-language=C# 4 | *.tex linguist-language=C# 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | .vs/ 4 | *.suo 5 | *.orig 6 | .sonarqube/ -------------------------------------------------------------------------------- /HtKit/AppPath.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:AppPath.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.IO; 11 | 12 | 13 | namespace HtKit; 14 | 15 | public static class AppPath 16 | { 17 | /// 18 | /// 获取程序目录(尾部带斜杠) 19 | /// 20 | /// 21 | /// 22 | public static string GetBaseDirectory(string path = "") 23 | { 24 | return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"MMClipboard\\{path}"); 25 | } 26 | 27 | /// 28 | /// 获取程序exe文件完整路径 29 | /// 30 | /// 31 | public static string GetApplicationExePath() 32 | { 33 | return Environment.ProcessPath; 34 | } 35 | 36 | /// 37 | /// 获取系统目录文件夹 38 | /// 39 | /// 40 | /// 41 | public static string GetSystemPath(Environment.SpecialFolder folder) 42 | { 43 | return Environment.GetFolderPath(folder); 44 | } 45 | } -------------------------------------------------------------------------------- /HtKit/AutoStart.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:AutoStart.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.IO; 11 | using System.Linq; 12 | using Microsoft.Win32; 13 | 14 | 15 | namespace HtKit; 16 | 17 | public abstract class AutoStart 18 | { 19 | #region 将程序快捷方式添加到系统启动目录,不需要管理员权限 20 | 21 | /// 22 | /// 系统自动启动目录 23 | /// 24 | private static string systemStartPath => Environment.GetFolderPath(Environment.SpecialFolder.Startup); 25 | 26 | /// 27 | /// 程序完整路径 28 | /// 29 | private static string appExePath => AppPath.GetApplicationExePath(); 30 | 31 | /// 32 | /// 设置开机启动 33 | /// 34 | /// 快捷方式名称 35 | /// 快捷方式描述 36 | /// 自启开关 37 | public static void SetAutoStart(string name, string desc, bool start = true) 38 | { 39 | var p = Path.Combine(systemStartPath, $"{name}.lnk"); 40 | if (File.Exists(p)) DeleteFile(p); 41 | if (start) QuickShort.CreateShortcut(systemStartPath, name, appExePath, desc); 42 | } 43 | 44 | /// 45 | /// 删除文件 46 | /// 47 | /// 路径 48 | private static void DeleteFile(string path) 49 | { 50 | var attr = File.GetAttributes(path); 51 | if (attr == FileAttributes.Directory) 52 | Directory.Delete(path, true); 53 | else 54 | File.Delete(path); 55 | } 56 | 57 | #endregion 将程序快捷方式添加到系统启动目录,不需要管理员权限 58 | 59 | #region 修改注册表,需要管理员权限 60 | 61 | /// 62 | /// 将本程序设为开启自启 63 | /// 64 | /// 自启开关 65 | /// 66 | public static bool SetStart(bool onOff) 67 | { 68 | // var appName = Process.GetCurrentProcess().MainModule?.ModuleName; 69 | var appPath = Environment.ProcessPath; 70 | return SelfRunning(onOff, "MMClipboard", appPath); 71 | } 72 | 73 | /// 74 | /// 判断注册键值对是否存在,即是否处于开机启动状态 75 | /// 76 | /// 键值名 77 | /// 78 | private static bool IsExistKey(string keyName) 79 | { 80 | try 81 | { 82 | var local = Registry.LocalMachine; 83 | var runs = local.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); 84 | if (runs == null) 85 | { 86 | var key2 = local.CreateSubKey("SOFTWARE"); 87 | var key3 = key2?.CreateSubKey("Microsoft"); 88 | var key4 = key3?.CreateSubKey("Windows"); 89 | var key5 = key4?.CreateSubKey("CurrentVersion"); 90 | var key6 = key5?.CreateSubKey("Run"); 91 | runs = key6; 92 | } 93 | var runsName = runs?.GetValueNames(); 94 | if (runsName != null) 95 | if (runsName.Any(strName => strName == keyName)) 96 | return true; 97 | local.Close(); 98 | return false; 99 | } 100 | catch (Exception e) 101 | { 102 | e.Debug(); 103 | return false; 104 | } 105 | } 106 | 107 | /// 108 | /// 写入或删除注册表键值对,即设为开机启动或开机不启动 109 | /// 110 | /// 是否开机启动 111 | /// 应用程序名 112 | /// 应用程序路径带程序名 113 | /// 114 | private static bool SelfRunning(bool isStart, string exeName, string path) 115 | { 116 | try 117 | { 118 | var local = Registry.LocalMachine; 119 | var key = local.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); 120 | if (key == null) local.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); 121 | //若开机自启动则添加键值对 122 | if (isStart) 123 | { 124 | key?.SetValue(exeName, "\"" + path + "\" -autorun"); 125 | key?.Close(); 126 | } 127 | else //否则删除键值对 128 | { 129 | if (IsExistKey(exeName)) 130 | { 131 | key?.DeleteValue(exeName); 132 | key?.Close(); 133 | } 134 | } 135 | } 136 | catch (Exception ex) 137 | { 138 | ex.Message.Log(); 139 | return false; 140 | //throw; 141 | } 142 | 143 | return true; 144 | } 145 | 146 | #endregion 修改注册表,需要管理员权限 147 | } -------------------------------------------------------------------------------- /HtKit/ChooseFileManager.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:ChooseFileManager.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Diagnostics; 11 | using System.Runtime.InteropServices; 12 | using Microsoft.Win32; 13 | 14 | 15 | namespace HtKit; 16 | 17 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 18 | internal class OpenDialogFile 19 | { 20 | public int structSize = 0; 21 | public IntPtr dlgOwner = IntPtr.Zero; 22 | public IntPtr instance = IntPtr.Zero; 23 | public string filter = null; 24 | public string customFilter = null; 25 | public int maxCustFilter = 0; 26 | public int filterIndex = 0; 27 | public string file = null; 28 | public int maxFile = 0; 29 | public string fileTitle = null; 30 | public int maxFileTitle = 0; 31 | public string initialDir = null; 32 | public string title = null; 33 | public int flags = 0; 34 | public short fileOffset = 0; 35 | public short fileExtension = 0; 36 | public string defExt = null; 37 | public IntPtr custData = IntPtr.Zero; 38 | public IntPtr hook = IntPtr.Zero; 39 | public string templateName = null; 40 | public IntPtr reservedPtr = IntPtr.Zero; 41 | public int reservedInt = 0; 42 | public int flagsEx = 0; 43 | } 44 | 45 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 46 | internal class OpenDialogDir 47 | { 48 | public IntPtr hwndOwner = IntPtr.Zero; 49 | public IntPtr pidlRoot = IntPtr.Zero; 50 | public string pszDisplayName = null; 51 | public string lpszTitle = null; 52 | public uint ulFlags = 0; 53 | public IntPtr lpfn = IntPtr.Zero; 54 | public IntPtr lParam = IntPtr.Zero; 55 | public int iImage = 0; 56 | } 57 | 58 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 59 | internal struct OpenFileName 60 | { 61 | public int structSize; 62 | public IntPtr dlgOwner; 63 | public IntPtr instance; 64 | public String filter; 65 | public String customFilter; 66 | public int maxCustFilter; 67 | public int filterIndex; 68 | public string file; 69 | public int maxFile; 70 | public String fileTitle; 71 | public int maxFileTitle; 72 | public String initialDir; 73 | public String title; 74 | public int flags; 75 | public short fileOffset; 76 | public short fileExtension; 77 | public String defExt; 78 | public IntPtr custData; 79 | public IntPtr hook; 80 | public String templateName; 81 | public IntPtr reservedPtr; 82 | public int reservedInt; 83 | public int flagsEx; 84 | } 85 | 86 | public static class ChooseFileManager 87 | { 88 | #region Window 89 | 90 | [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)] 91 | private static extern bool GetOpenFileName([In] [Out] OpenFileName ofn); 92 | 93 | [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)] 94 | private static extern bool GetSaveFileName([In] [Out] OpenFileName ofn); 95 | 96 | [DllImport("shell32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)] 97 | private static extern IntPtr SHBrowseForFolder([In] [Out] OpenDialogDir ofn); 98 | 99 | [DllImport("shell32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)] 100 | private static extern bool SHGetPathFromIDList([In] IntPtr pidl, [In] [Out] char[] fileName); 101 | 102 | #endregion Window 103 | 104 | /* 105 | 筛选器字符串应包含筛选器的说明,后跟竖线(|)和筛选模式。多个筛选器说明和模式对还必须以竖线分隔。在一个筛选器模式中的多个扩展名必须用分号分隔。例如: \"图像文件(*.bmp, *.jpg)|*.bmp;*.jpg|所有文件(*.*)|*.*\" 106 | */ 107 | public const string AllFILTER = "所有文件(*.*)|*."; 108 | public const string TxtFILTER = "txt文件(*.txt*)|*.txt"; 109 | public const string ImageFILTER = "图片(*.jpg,*.png)|*.jpg;*.png"; 110 | public const string AudioFILTER = "音乐文件(*.mp3)|*.mp3"; 111 | public const string PDFFILTER = "pdf文件(*.pdf)|*.pdf"; 112 | public const string DOCFILTER = "word文档(*.doc,*.docx)|*.doc;*.docx"; 113 | 114 | /// 115 | /// 选择文件 116 | /// 117 | /// 返回选择文件夹的路径 118 | /// 文件类型筛选器 119 | /// 是否多选 120 | public static void SelectFile(Action callback, string filter = AllFILTER, bool isChooseMore = true) 121 | { 122 | OpenFileDialog dialog = new() 123 | { 124 | DefaultExt = ".png", 125 | Filter = filter, 126 | InitialDirectory = @"C:\Users\PC\Pictures\" 127 | }; 128 | // 打开选择框选择 129 | var result = dialog.ShowDialog(); 130 | callback?.Invoke(result == true ? dialog.FileName : ""); 131 | } 132 | 133 | /// 134 | /// 选择图片 135 | /// 136 | /// 137 | /// 138 | public static void SelectImageFile(Action callback, bool isChooseMore = true) 139 | { 140 | OpenFileDialog dialog = new() 141 | { 142 | DefaultExt = ".png", 143 | Filter = ImageFILTER, 144 | InitialDirectory = @"C:\Users\PC\Pictures\" 145 | }; 146 | // 打开选择框选择 147 | var result = dialog.ShowDialog(); 148 | callback?.Invoke(result == true ? dialog.FileName : ""); 149 | } 150 | 151 | /// 152 | /// 保存文件 153 | /// 154 | /// 文件默认后缀 155 | /// 文件类型 156 | /// 157 | public static void GetSavePath(Action callBack, string fileExt, string filter = AllFILTER) 158 | { 159 | var pth = new OpenFileName(); 160 | pth.structSize = Marshal.SizeOf(pth); 161 | pth.filter = filter; 162 | pth.file = new string(new char[256]); 163 | pth.maxFile = pth.file.Length; 164 | pth.fileTitle = new string(new char[64]); 165 | pth.maxFileTitle = pth.fileTitle.Length; 166 | pth.initialDir = @"C:\User\Desktop"; //默认路径 167 | pth.title = "保存文件"; 168 | pth.defExt = fileExt; 169 | pth.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008; 170 | if (!GetSaveFileName(pth)) return; 171 | var filepath = pth.file; //选择的文件路径; 172 | callBack?.Invoke(filepath); 173 | } 174 | 175 | /// 176 | /// 调用WindowsExploer 并返回所选文件夹路径 177 | /// 178 | /// 179 | /// 打开对话框的标题 180 | /// 所选文件夹路径 181 | public static void GetPathFromWindowsExplorer(Action callback, string dialogTitle = "请选择保存路径") 182 | { 183 | try 184 | { 185 | var ofn2 = new OpenDialogDir 186 | { 187 | pszDisplayName = new string(new char[2048]) 188 | }; 189 | ; // 存放目录路径缓冲区 190 | ofn2.lpszTitle = dialogTitle; // 标题 191 | ofn2.ulFlags = 0x00000040; // 新的样式,带编辑框 192 | var pidlPtr = SHBrowseForFolder(ofn2); 193 | 194 | var charArray = new char[2048]; 195 | 196 | for (var i = 0; i < 2048; i++) charArray[i] = '\0'; 197 | 198 | SHGetPathFromIDList(pidlPtr, charArray); 199 | var res = new string(charArray); 200 | res = res[..res.IndexOf('\0')]; 201 | callback?.Invoke(res); 202 | } 203 | catch (Exception e) 204 | { 205 | e.Debug(); 206 | callback?.Invoke("选择出错,请重试"); 207 | } 208 | } 209 | 210 | /// 211 | /// 打开目录 212 | /// 213 | /// 将要打开的文件目录 214 | public static void OpenFolder(string path) 215 | { 216 | Process.Start("explorer.exe", path); 217 | } 218 | } -------------------------------------------------------------------------------- /HtKit/Debug.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:Debug.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Collections; 11 | using System.IO; 12 | using System.Linq; 13 | using System.Runtime.CompilerServices; 14 | 15 | 16 | namespace HtKit 17 | { 18 | public static class Debug 19 | { 20 | private static string LogDirPath 21 | { 22 | get 23 | { 24 | var p = AppPath.GetBaseDirectory(@"Logs"); 25 | if (!Directory.Exists(p)) 26 | Directory.CreateDirectory(p!); 27 | return p; 28 | } 29 | } 30 | 31 | public static void Log(object msg, 32 | [CallerFilePath] string filePath = "", 33 | [CallerLineNumber] int num = 0, 34 | [CallerMemberName] string name = "", bool isLog = false) 35 | { 36 | System.Diagnostics.Debug.WriteLine($"在 {filePath}, 第 {num} 行, {name} 方法中, Log: ↓↓↓\n{msg}"); 37 | #if RELEASE 38 | if (isLog) 39 | { 40 | WriteLog(msg); 41 | } 42 | #endif 43 | } 44 | 45 | // 写入本地日志文件 46 | private static void WriteLog(object msg) 47 | { 48 | try 49 | { 50 | var now = DateTime.Now; 51 | var p = Path.Combine(LogDirPath, $"{now:yyyy-MM-dd}.txt"); 52 | if (!File.Exists(p)) 53 | File.Create(p).Close(); 54 | File.AppendAllText(p, $"{now:HH:mm:ss.fff} {msg}\n"); 55 | } 56 | catch (Exception ex) 57 | { 58 | ex.Log(); 59 | } 60 | } 61 | } 62 | } 63 | 64 | public static class DebugExtension 65 | { 66 | public static ICollection DebugAny(this ICollection target, 67 | [CallerFilePath] string filePath = "", 68 | [CallerLineNumber] int num = 0, 69 | [CallerMemberName] string name = "") 70 | { 71 | var str = target.Cast().Aggregate("", (current, item) => current + $"{item}\n"); 72 | HtKit.Debug.Log(str[..^1], filePath, num, name); 73 | return target; 74 | } 75 | 76 | public static T Debug(this T target, 77 | [CallerFilePath] string filePath = "", 78 | [CallerLineNumber] int num = 0, 79 | [CallerMemberName] string name = "") 80 | { 81 | HtKit.Debug.Log(target, filePath, num, name); 82 | return target; 83 | } 84 | 85 | public static T Log(this T target, 86 | [CallerFilePath] string filePath = "", 87 | [CallerLineNumber] int num = 0, 88 | [CallerMemberName] string name = "") 89 | { 90 | HtKit.Debug.Log(target, filePath, num, name, true); 91 | return target; 92 | } 93 | } -------------------------------------------------------------------------------- /HtKit/Dispatch.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:Dispatch.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Windows; 11 | 12 | 13 | namespace HtKit; 14 | 15 | public static class Dispatch 16 | { 17 | /// 18 | /// 回到主线程(同步) 19 | /// 20 | /// 21 | public static void BackToMainThreadSync(Action ac) 22 | { 23 | Application.Current.Dispatcher.Invoke(ac); 24 | } 25 | 26 | /// 27 | /// 回到主线程(异步) 28 | /// 29 | /// 30 | public static async void BackToMainThreadAsync(Action ac) 31 | { 32 | await Application.Current.Dispatcher.InvokeAsync(ac); 33 | } 34 | } -------------------------------------------------------------------------------- /HtKit/Downloader/DownloadConfig.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:DownloadConfig.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | 11 | 12 | namespace HtKit; 13 | 14 | public class DownloadConfig 15 | { 16 | private int _chunkCount = 1; 17 | private long _maximumBytesPerSecond = long.MaxValue; 18 | private int _parallelCount; 19 | 20 | /// 21 | /// 数据缓冲区的buffer大小 默认1024 * 50 22 | /// 23 | public int BufferBlockSize { get; set; } = 1024 * 50; 24 | 25 | /// 26 | /// 下载前检查磁盘空间 默认true 27 | /// 28 | public bool CheckDiskSizeBeforeDownload { get; set; } = true; 29 | 30 | /// 31 | /// 切片数量 默认为1(不切片) 32 | /// 33 | public int ChunkCount 34 | { 35 | get => _chunkCount; 36 | set => _chunkCount = Math.Max(1, value); 37 | } 38 | 39 | /// 40 | /// 最大的下载速度 默认无限制 41 | /// 42 | public long MaximumBytesPerSecond 43 | { 44 | get => _maximumBytesPerSecond; 45 | set => _maximumBytesPerSecond = value <= 0 ? long.MaxValue : value; 46 | } 47 | 48 | /// 49 | /// 重试次数 默认无限制 50 | /// 51 | public int MaxTryAgainOnFail { get; set; } = int.MaxValue; 52 | 53 | /// 54 | /// 是否并行下载 默认为false 55 | /// 56 | public bool ParallelDownload { get; set; } = false; 57 | 58 | /// 59 | /// 并行任务数量 默认为0 60 | /// 61 | public int ParallelCount 62 | { 63 | get => _parallelCount <= 0 ? ChunkCount : _parallelCount; 64 | set => _parallelCount = value; 65 | } 66 | 67 | /// 68 | /// 开启断点下载 69 | /// 70 | public bool RangeDownload { get; set; } = false; 71 | 72 | /// 73 | /// 起始范围 默认(0,0) 74 | /// 75 | public (long, long) Range { get; set; } = (0, 0); 76 | 77 | /// 78 | /// 下载超时时间(毫秒) 默认1000 79 | /// 80 | public int Timeout { get; set; } = 1000; 81 | } -------------------------------------------------------------------------------- /HtKit/Downloader/DownloadEventArgs.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:DownloadEventArgs.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | namespace HtKit; 10 | 11 | public class DownloadStartedEventArgs 12 | { 13 | /// 14 | /// 文件名 15 | /// 16 | public string fileName { get; set; } 17 | 18 | /// 19 | /// 文件大小 20 | /// 21 | public long fileSize { get; set; } 22 | } 23 | 24 | public class ProgressChangedEventArgs 25 | { 26 | /// 27 | /// 下载进度 28 | /// 29 | public double progress { get; set; } 30 | 31 | /// 32 | /// 总下载量 33 | /// 34 | public long readBytes { get; set; } 35 | 36 | /// 37 | /// 瞬时速度 38 | /// 39 | public double instantSpeed { get; set; } 40 | 41 | /// 42 | /// 平均速度 43 | /// 44 | public double averageSpeed { get; set; } 45 | } 46 | 47 | public class DownloadFailedEventArgs 48 | { 49 | /// 50 | /// 错误信息 51 | /// 52 | public string error { get; set; } 53 | } -------------------------------------------------------------------------------- /HtKit/Downloader/Downloader.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:Downloader.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System.Threading.Tasks; 10 | 11 | 12 | namespace HtKit; 13 | 14 | public abstract class Downloader 15 | { 16 | /// 17 | /// 默认的下载方式 18 | /// 19 | /// 20 | /// 21 | /// 22 | /// 23 | /// 24 | /// 25 | /// 26 | /// 27 | public static Task DownloadFile(string url, string path, DownloadStartedChangedEventHandler started, DownloadProgressChangedEventHandler progressChanged, 28 | DownloadCompletedEventHandler completed, DownloadFailedEventHandler failed, DownloadConfig config = default) 29 | { 30 | DownloadService service = new(url, path, config); 31 | service.downloadStarted += started; 32 | service.progressChanged += progressChanged; 33 | service.downloadCompleted += completed; 34 | service.downloadFailed += failed; 35 | return service.StartDownloadAsync(); 36 | } 37 | } -------------------------------------------------------------------------------- /HtKit/Extension/DateExtension.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:DateExtension.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | 11 | 12 | public static class DateExtension 13 | { 14 | /// 15 | /// 获取周信息 16 | /// 17 | /// 18 | /// 19 | public static string Ht_GetWeek(this DateTime target) 20 | { 21 | return target.DayOfWeek switch 22 | { 23 | DayOfWeek.Monday => "星期一", 24 | DayOfWeek.Tuesday => "星期二", 25 | DayOfWeek.Wednesday => "星期三", 26 | DayOfWeek.Thursday => "星期四", 27 | DayOfWeek.Friday => "星期五", 28 | DayOfWeek.Saturday => "星期六", 29 | DayOfWeek.Sunday => "星期日", 30 | _ => "" 31 | }; 32 | } 33 | } -------------------------------------------------------------------------------- /HtKit/Extension/ImageExtension.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:ImageExtension.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Windows.Controls; 11 | using System.Windows.Media.Imaging; 12 | 13 | 14 | public static class ImageExtension 15 | { 16 | /// 17 | /// 加载目标位置图片 18 | /// 19 | /// 20 | /// 21 | public static void Ht_Load(this Image target, string url) 22 | { 23 | target.Source = BitmapFrame.Create(new Uri(url), BitmapCreateOptions.None, BitmapCacheOption.Default); 24 | } 25 | } -------------------------------------------------------------------------------- /HtKit/Extension/IntExtension.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:IntExtension.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | 11 | 12 | public static class IntExtension 13 | { 14 | /// 15 | /// 遍历n次 16 | /// 17 | /// 18 | /// 19 | public static void Ht_For(this int target, Action ac) 20 | { 21 | if (target <= 0 || ac == null) return; 22 | for (var i = 0; i < target; i++) ac(); 23 | } 24 | 25 | /// 26 | /// 遍历n次 带参数 27 | /// 28 | /// 29 | /// 30 | public static void Ht_For(this int target, Action ac) 31 | { 32 | if (target <= 0 || ac == null) return; 33 | for (var i = 0; i < target; i++) ac(i); 34 | } 35 | 36 | /// 37 | /// 倒循环 带参数 38 | /// 39 | /// 40 | /// 41 | public static void Ht_InversionFor(this int target, Action ac) 42 | { 43 | if (target <= 0 || ac == null) return; 44 | for (var i = target; i > 0; i--) ac(i); 45 | } 46 | 47 | /// 48 | /// 阿拉伯数字转中文数字 49 | /// 50 | /// 51 | /// 是否大写(大写:壹佰贰拾叁,小写:一百二十三) 52 | /// 53 | public static string Ht_ToChineseNumber(this int target, bool isUpper = true) 54 | { 55 | if (target == 0) 56 | return "零"; 57 | 58 | var x = target.ToString(); 59 | var result = ""; 60 | string[] pArrayNum = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }; 61 | string[] pArrayDigit = { "", "拾", "佰", "仟" }; 62 | string[] pArrayUnits = { "", "万", "亿", "万亿" }; 63 | 64 | if (!isUpper) 65 | { 66 | pArrayNum = new[] { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" }; 67 | pArrayDigit = new[] { "", "十", "百", "千" }; 68 | } 69 | 70 | var finger = 0; 71 | var pIntM = x.Length % 4; 72 | int pIntK; 73 | if (pIntM > 0) 74 | pIntK = x.Length / 4 + 1; 75 | else 76 | pIntK = x.Length / 4; 77 | 78 | //外层循环,四位一组,每组最后加上单位: ",万亿,",",亿,",",万," 79 | for (var i = pIntK; i > 0; i--) 80 | { 81 | var pIntL = 4; 82 | if (i == pIntK && pIntM != 0) 83 | pIntL = pIntM; 84 | 85 | //得到一组四位数 86 | var four = x.Substring(finger, pIntL); 87 | var P_int_l = four.Length; 88 | //内层循环在该组中的每一位数上循环 89 | for (var j = 0; j < P_int_l; j++) 90 | { 91 | //处理组中的每一位数加上所在的位 92 | var n = Convert.ToInt32(four.Substring(j, 1)); 93 | if (n == 0) 94 | { 95 | if (j < P_int_l - 1 && Convert.ToInt32(four.Substring(j + 1, 1)) > 0 && !result.EndsWith(pArrayNum[n])) 96 | result += pArrayNum[n]; 97 | } 98 | else 99 | { 100 | if (!(n == 1 && result.EndsWith(pArrayNum[0]) | (result.Length == 0) && j == P_int_l - 2)) 101 | result += pArrayNum[n]; 102 | result += pArrayDigit[P_int_l - j - 1]; 103 | } 104 | } 105 | finger += pIntL; 106 | 107 | if (i < pIntK) 108 | { 109 | if (Convert.ToInt32(four) != 0) 110 | result += pArrayUnits[i - 1]; 111 | } 112 | else 113 | { 114 | //处理最高位的一组,最后必须加上单位 115 | result += pArrayUnits[i - 1]; 116 | } 117 | } 118 | return result; 119 | } 120 | } -------------------------------------------------------------------------------- /HtKit/Extension/ListExtension.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:ListExtension.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Collections.Generic; 11 | 12 | 13 | public static class ListExtension 14 | { 15 | /// 16 | /// 遍历 17 | /// 18 | /// 19 | /// 20 | /// 21 | public static void Ht_For(this List target, Action ac) 22 | { 23 | if (target.Count <= 0 || ac == null) return; 24 | for (var i = 0; i < target.Count; i++) ac(i, target[i]); 25 | } 26 | 27 | /// 28 | /// 反向遍历 29 | /// 30 | /// 31 | /// 32 | /// 33 | public static void Ht_InversionFor(this List target, Action ac) 34 | { 35 | if (target.Count <= 0 || ac == null) return; 36 | for (var i = target.Count - 1; i >= 0; i--) ac(i, target[i]); 37 | } 38 | } -------------------------------------------------------------------------------- /HtKit/FileHelper.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:FileHelper.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Collections.Generic; 11 | using System.IO; 12 | using System.Linq; 13 | using System.Text; 14 | using System.Threading.Tasks; 15 | 16 | 17 | namespace HtKit; 18 | 19 | public static class FileHelper 20 | { 21 | /// 22 | /// 将字节流写入到文件 23 | /// 24 | /// 文件地址 25 | /// 数据 26 | /// 完成回调 27 | /// 是否为新增 28 | /// 29 | public static async void WriteBytesToFile(string path, byte[] data, Action complete = null, bool isAppend = false) 30 | { 31 | if (path is null || path.Length == 0) 32 | { 33 | "地址不能为空".Debug(); 34 | return; 35 | } 36 | 37 | if (!File.Exists(path)) 38 | { 39 | await using Stream fs = File.Create(path); 40 | await fs.FlushAsync(); 41 | fs.Close(); 42 | } 43 | 44 | var mode = FileMode.OpenOrCreate; 45 | if (isAppend) mode = FileMode.Append; 46 | 47 | await Task.Run(async () => 48 | { 49 | await using Stream stream = new FileStream(path, mode, FileAccess.Write); 50 | await stream.WriteAsync(data); 51 | await stream.FlushAsync(); 52 | stream.Close(); 53 | Dispatch.BackToMainThreadSync(() => complete?.Invoke()); 54 | }); 55 | } 56 | 57 | /// 58 | /// 将字符串写入到文件(UTF8编码) 59 | /// 60 | /// 文件地址 61 | /// 数据字符串 62 | /// 63 | /// 完成回调 64 | /// 是否为新增 65 | /// 66 | public static void WriteStringToFile(string path, string dataStr, Encoding encoding, Action complete = null, bool isAppend = false) 67 | { 68 | if (path.Ht_IsEmpty()) 69 | throw new Exception("地址不能为空"); 70 | 71 | WriteBytesToFile(path, encoding.GetBytes(dataStr), complete, isAppend); 72 | } 73 | 74 | /// 75 | /// 从指定文件读取字节流(异步) 76 | /// 77 | /// 文件地址 78 | /// 完成回调 79 | /// 80 | public static async void ReadBytesFromFileAsync(string path, Action ac) 81 | { 82 | if (path.Ht_IsEmpty()) 83 | throw new Exception("地址不能为空"); 84 | 85 | if (!File.Exists(path)) 86 | throw new Exception("文件不存在"); 87 | 88 | await Task.Run(async () => 89 | { 90 | var bytes = new byte[1024]; 91 | var result = new List(); 92 | await using Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read); 93 | while (true) 94 | { 95 | var r = await stream.ReadAsync(bytes); 96 | if (r == 0) 97 | { 98 | Dispatch.BackToMainThreadSync(() => ac.Invoke(result.ToArray())); 99 | break; 100 | } 101 | result.AddRange(bytes.ToList().GetRange(0, r)); 102 | } 103 | await stream.FlushAsync(); 104 | stream.Close(); 105 | }); 106 | } 107 | 108 | /// 109 | /// 从文件读取字符串 110 | /// 111 | /// 文件地址 112 | /// 完成回调 113 | /// 字符串编码方式 114 | /// 115 | public static void ReadStringFromFileAsync(string path, Action ac, Encoding encoding) 116 | { 117 | if (path.Ht_IsEmpty()) 118 | throw new Exception("地址不能为空"); 119 | 120 | if (!File.Exists(path)) 121 | throw new Exception("文件不存在"); 122 | 123 | ReadBytesFromFileAsync(path, (bt) => ac(encoding.GetString(bt))); 124 | } 125 | 126 | /// 127 | /// 获取文件信息 byte 128 | /// 129 | /// 130 | /// 131 | /// 132 | public static long GetFileSize(string filePath) 133 | { 134 | if (!File.Exists(filePath)) 135 | throw new Exception("文件不存在"); 136 | var info = new FileInfo(filePath); 137 | return info.Length; 138 | } 139 | } -------------------------------------------------------------------------------- /HtKit/HtColor.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:HtColor.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Windows.Media; 11 | 12 | 13 | namespace HtKit; 14 | 15 | public static class HtColor 16 | { 17 | /// 18 | /// 通过Hex字符串获取颜色 19 | /// 20 | /// 21 | /// 22 | /// 23 | public static Color ColorWithHex(string hex) 24 | { 25 | return (Color)ColorConverter.ConvertFromString(hex)!; 26 | } 27 | 28 | /// 29 | /// 使用Color初始化一个Brush 30 | /// 31 | /// 32 | /// 33 | public static SolidColorBrush GetBrushWithColor(Color color) 34 | { 35 | return new SolidColorBrush(color); 36 | } 37 | 38 | /// 39 | /// 使用颜色字符串初始化一个Brush 40 | /// 41 | /// 42 | /// 43 | public static SolidColorBrush GetBrushWithString(string colorString) 44 | { 45 | return new SolidColorBrush(ColorWithHex(colorString)); 46 | } 47 | } -------------------------------------------------------------------------------- /HtKit/HtKit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0-windows10.0.17763.0 5 | disable 6 | true 7 | False 8 | HtKit 9 | Ht 10 | Ht 11 | Copyright © 2023 Ht. All rights reserved. 12 | 13 | 14 | 15 | embedded 16 | 17 | 18 | 19 | embedded 20 | 21 | 22 | 23 | 24 | tlbimp 25 | 0 26 | 1 27 | f935dc20-1cf0-11d0-adb9-00c04fd58a0b 28 | 0 29 | false 30 | true 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /HtKit/HtZipHelper.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:HtZipHelper.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.IO; 11 | using System.Threading.Tasks; 12 | using ICSharpCode.SharpZipLib.Core; 13 | using ICSharpCode.SharpZipLib.Zip; 14 | 15 | 16 | namespace Escher.Tool; 17 | 18 | public static class HtZipHelper 19 | { 20 | public static async Task Unzip(string zipPath, string toDir, Action progressAc, Action completeAc, Action failAc) 21 | { 22 | if (string.IsNullOrEmpty(toDir)) return; 23 | if (!Directory.Exists(toDir)) 24 | Directory.CreateDirectory(toDir); 25 | if (!File.Exists(zipPath)) 26 | return; 27 | await Task.Run(() => 28 | { 29 | try 30 | { 31 | using FileStream fs = new(zipPath, FileMode.Open, FileAccess.Read); 32 | using ZipFile zf = new(fs); 33 | var totalEntries = zf.Count; 34 | var currentEntry = 0; 35 | foreach (ZipEntry zipEntry in zf) 36 | { 37 | if (!zipEntry.IsFile) 38 | continue; // 跳过非文件项 39 | currentEntry++; 40 | progressAc?.Invoke(currentEntry, totalEntries); 41 | var entryFileName = zipEntry.Name; 42 | var buffer = new byte[4096]; 43 | 44 | var fullZipToPath = Path.Combine(toDir, entryFileName); 45 | var directoryName = Path.GetDirectoryName(fullZipToPath); 46 | 47 | if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName)) Directory.CreateDirectory(directoryName); 48 | 49 | using var zipStream = zf.GetInputStream(zipEntry); 50 | using var streamWriter = File.Create(fullZipToPath); 51 | StreamUtils.Copy(zipStream, streamWriter, buffer); 52 | } 53 | fs.Close(); 54 | completeAc?.Invoke(); 55 | } 56 | catch (Exception e) 57 | { 58 | failAc?.Invoke(e.Message.Log()); 59 | } 60 | }); 61 | } 62 | } -------------------------------------------------------------------------------- /HtKit/MemoryHelper.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:MemoryHelper.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Diagnostics; 11 | using System.Runtime.InteropServices; 12 | using Microsoft.Win32; 13 | 14 | 15 | namespace HtKit; 16 | 17 | public class MemoryHelper 18 | { 19 | private void SetDate() 20 | { 21 | CreateKey(); 22 | var currentUser = Registry.CurrentUser; 23 | var registryKey = currentUser.OpenSubKey("SOFTWARE\\DevExpress\\Components", true); 24 | registryKey!.GetValue("LastAboutShowedTime"); 25 | var value = DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss"); 26 | registryKey!.SetValue("LastAboutShowedTime", value); 27 | currentUser.Dispose(); 28 | } 29 | 30 | [DllImport("kernel32.dll")] 31 | private static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max); 32 | 33 | public static void FlushMemory() 34 | { 35 | GC.Collect(); 36 | GC.WaitForPendingFinalizers(); 37 | if (Environment.OSVersion.Platform == PlatformID.Win32NT) SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1); 38 | } 39 | 40 | private static void CreateKey() 41 | { 42 | var currentUser = Registry.CurrentUser; 43 | if (currentUser.OpenSubKey(@"SOFTWARE\DevExpress\Components", true) == null) 44 | { 45 | var registryKey = currentUser.CreateSubKey(@"SOFTWARE\DevExpress\Components"); 46 | if (registryKey is null) return; 47 | registryKey.CreateSubKey("LastAboutShowedTime")?.SetValue("LastAboutShowedTime", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss")); 48 | registryKey.CreateSubKey("DisableSmartTag")?.SetValue("LastAboutShowedTime", false); 49 | registryKey.CreateSubKey("SmartTagWidth")?.SetValue("LastAboutShowedTime", 350); 50 | } 51 | 52 | currentUser.Dispose(); 53 | } 54 | 55 | // public void Cracker(int sleepSpan = 30) 56 | // { 57 | // Task.Factory.StartNew(delegate 58 | // { 59 | // while (true) 60 | // try 61 | // { 62 | // SetDate(); 63 | // FlushMemory(); 64 | // Thread.Sleep(TimeSpan.FromSeconds(sleepSpan)); 65 | // } 66 | // catch (Exception) 67 | // { 68 | // // ignored 69 | // } 70 | // }); 71 | // } 72 | } -------------------------------------------------------------------------------- /HtKit/NetWorking/NetHelper.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:NetHelper.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-8-15 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Net; 12 | using System.Net.Http; 13 | using System.Runtime.InteropServices; 14 | using Newtonsoft.Json; 15 | 16 | 17 | namespace HtKit.NetWorking; 18 | 19 | public delegate void NetSuccessDelegate(T data); 20 | 21 | public delegate void NetFailDelegate(string error); 22 | 23 | public static class NetHelper 24 | { 25 | private static HttpClient httpClient 26 | { 27 | get 28 | { 29 | _httpClient ??= new HttpClient 30 | { 31 | Timeout = TimeSpan.FromSeconds(15) 32 | }; 33 | return _httpClient; 34 | } 35 | } 36 | 37 | private static HttpClient _httpClient; 38 | 39 | /// 40 | /// Get请求(返回Json字符串) 41 | /// 42 | /// api 43 | /// 成功回调 44 | /// 失败回调 45 | public static async void GetResponse(string url, NetSuccessDelegate success, NetFailDelegate fail = null) 46 | { 47 | try 48 | { 49 | var response = await httpClient.GetAsync(url); 50 | 51 | var dataStr = await response.Content.ReadAsStringAsync(); 52 | 53 | if (response.StatusCode == HttpStatusCode.OK) 54 | success?.Invoke(dataStr); 55 | else 56 | fail?.Invoke(dataStr); 57 | } 58 | catch (Exception e) 59 | { 60 | e.Message.Log(); 61 | fail?.Invoke(e.Message); 62 | } 63 | } 64 | 65 | /// 66 | /// Get请求(返回指定泛型) 67 | /// 68 | /// api 69 | /// 成功回调 70 | /// 失败回调 71 | public static async void GetResponse(string url, NetSuccessDelegate success, NetFailDelegate fail = null) 72 | { 73 | var response = await httpClient.GetAsync(url); 74 | 75 | var dataStr = await response.Content.ReadAsStringAsync(); 76 | 77 | if (response.StatusCode == HttpStatusCode.OK) 78 | success?.Invoke(JsonConvert.DeserializeObject(dataStr)!); 79 | else 80 | fail?.Invoke(dataStr); 81 | } 82 | 83 | /// 84 | /// Post请求 85 | /// 86 | /// api 87 | /// 参数字典 88 | /// 成功回调 89 | /// 失败回调 90 | public static async void PostResponse(string url, Dictionary parm, NetSuccessDelegate success, NetFailDelegate fail = null) 91 | { 92 | HttpContent content = new StringContent(JsonConvert.SerializeObject(parm)); 93 | 94 | var response = await httpClient.PostAsync(url, content); 95 | 96 | var dataStr = await response.Content.ReadAsStringAsync(); 97 | 98 | if (response.StatusCode == HttpStatusCode.OK) 99 | success?.Invoke(dataStr); 100 | else 101 | fail?.Invoke(dataStr); 102 | } 103 | 104 | [DllImport("wininet.dll", EntryPoint = "InternetGetConnectedState")] 105 | public static extern bool InternetGetConnectedState(out int conState, int reader); 106 | 107 | public static bool IsHaveNet() 108 | { 109 | var i = 0; 110 | return InternetGetConnectedState(out i, i); 111 | } 112 | } -------------------------------------------------------------------------------- /HtKit/QuickShort.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:QuickShort.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.IO; 11 | using IWshRuntimeLibrary; 12 | using File = System.IO.File; 13 | 14 | 15 | namespace HtKit; 16 | 17 | /// 18 | /// 快捷方式相关 19 | /// 20 | public static class QuickShort 21 | { 22 | /// 23 | /// 自动获取桌面目录 24 | /// 25 | private static string desktopPath => Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); 26 | 27 | /// 28 | /// 在桌面上创建快捷方式 29 | /// 30 | /// 快捷方式名称 31 | public static void CreateDesktopQuick(string quickName = "") 32 | { 33 | var p = Path.Combine(desktopPath, $"{quickName}.lnk"); 34 | if (File.Exists(p)) File.Delete(p); 35 | CreateShortcut(desktopPath, quickName, AppPath.GetApplicationExePath()); 36 | } 37 | 38 | /// 39 | /// 向目标路径创建指定文件的快捷方式 40 | /// 41 | /// 目标目录 42 | /// 快捷方式名字 43 | /// 文件完全路径 44 | /// 描述 45 | /// 图标地址 46 | /// 成功或失败 47 | public static bool CreateShortcut(string directory, string shortcutName, string targetPath, string description = null, string iconLocation = null) 48 | { 49 | if (string.IsNullOrEmpty(directory)) return false; 50 | try 51 | { 52 | if (!Directory.Exists(directory)) Directory.CreateDirectory(directory); //目录不存在则创建 53 | //添加引用 Com 中搜索 Windows Script Host Object Model 54 | var shortcutPath = Path.Combine(directory, $"{shortcutName}.lnk"); //合成路径 55 | var shell = new WshShell(); 56 | var shortcut = (IWshShortcut)shell.CreateShortcut(shortcutPath); //创建快捷方式对象 57 | shortcut.TargetPath = targetPath; //指定目标路径 58 | shortcut.WorkingDirectory = Path.GetDirectoryName(targetPath); //设置起始位置 59 | shortcut.WindowStyle = 1; //设置运行方式,默认为常规窗口 60 | shortcut.Description = description; //设置备注 61 | shortcut.IconLocation = string.IsNullOrWhiteSpace(iconLocation) ? targetPath : iconLocation; //设置图标路径 62 | shortcut.Save(); //保存快捷方式 63 | return true; 64 | } 65 | catch (Exception ex) 66 | { 67 | ex.Message.Debug(); 68 | } 69 | return false; 70 | } 71 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-2024 Ht. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/App.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/App.xaml.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:App.xaml 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/8/15 12:17:56 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Diagnostics; 11 | using System.IO; 12 | using System.Text; 13 | using System.Threading; 14 | using System.Threading.Tasks; 15 | using System.Windows; 16 | using System.Windows.Input; 17 | using System.Windows.Threading; 18 | using Hardcodet.Wpf.TaskbarNotification; 19 | using HtKit; 20 | using MMClipboard.Tool; 21 | using MMClipboard.UserConfigs; 22 | 23 | 24 | namespace MMClipboard; 25 | 26 | /// 27 | /// Interaction logic for App.xaml 28 | /// 29 | public partial class App 30 | { 31 | public TaskbarIcon taskbarIcon; 32 | 33 | private static Mutex mutex; 34 | 35 | private const string UniqueEventName = "com.ht.mmclipboard.StartMainEvent"; 36 | 37 | private const string UniqueMutexName = "com.ht.mmclipboard"; 38 | 39 | private static EventWaitHandle eventWaitHandle; 40 | 41 | private const int InstanceMsg = 0x9823; 42 | 43 | protected override void OnStartup(StartupEventArgs e) 44 | { 45 | mutex = new Mutex(true, UniqueMutexName, out var isOwned); 46 | // 保证mutex不会被GC回收 47 | GC.KeepAlive(mutex); 48 | eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, UniqueEventName); 49 | if (!isOwned) 50 | { 51 | // 通知其他实例,do something... 52 | eventWaitHandle.Set(); 53 | // 退出当前实例程序 54 | Environment.Exit(0); 55 | } 56 | else 57 | { 58 | #if DEBUG 59 | RunSelf(); 60 | #else 61 | var identity = System.Security.Principal.WindowsIdentity.GetCurrent(); 62 | System.Security.Principal.WindowsPrincipal principal = new(identity); 63 | 64 | if (principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator)) 65 | { 66 | RunSelf(); 67 | } 68 | else 69 | { 70 | var startInfo = new ProcessStartInfo(Environment.ProcessPath ?? "") 71 | { 72 | UseShellExecute = true, 73 | Verb = "runas" 74 | }; 75 | try 76 | { 77 | Process.Start(startInfo); 78 | } 79 | catch (Exception ex) 80 | { 81 | ex.Message.Log(); 82 | } 83 | Current.Shutdown(); 84 | } 85 | #endif 86 | } 87 | } 88 | 89 | protected override void OnExit(ExitEventArgs e) 90 | { 91 | base.OnExit(e); 92 | DataBaseController.Close(); 93 | 94 | ClipboardListener.Remove(); 95 | // 启动更新程序 96 | if (!SharedInstance.Instance.isNeedUpdate) 97 | return; 98 | var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UpdateTool.exe"); 99 | if (!File.Exists(path)) return; 100 | var info = new ProcessStartInfo(path) 101 | { 102 | Arguments = "com.ht.mmclipboard" 103 | }; 104 | Process.Start(info); 105 | } 106 | 107 | private void RunSelf() 108 | { 109 | // 单例应用 110 | var thread = new Thread(() => 111 | { 112 | while (eventWaitHandle.WaitOne()) 113 | Dispatcher.CurrentDispatcher.InvokeAsync(SharedInstance.ShowMainWindow); 114 | }) 115 | { 116 | IsBackground = true 117 | }; 118 | thread.Start(); 119 | 120 | // 读取用户配置 121 | UserConfig.ReadConfig(); 122 | 123 | // 注册快捷键 124 | HotKeyManager.RegisterHotKey_ShowMainWindow(UserConfig.Default.config.key, UserConfig.Default.config.modifierKeys); 125 | HotKeyManager.RegisterHotKey_ShowPhraseWindow(Key.Oem3, ModifierKeys.Alt); 126 | SharedInstance.Instance.registerHotKeyAction = (m, k) => 127 | { 128 | HotKeyManager.RegisterHotKey_ShowMainWindow(k, m); 129 | HotKeyManager.RegisterHotKey_ShowPhraseWindow(Key.Oem3, ModifierKeys.Alt); 130 | }; 131 | 132 | // 监听剪贴板事件 133 | ClipboardListener.Add(); 134 | 135 | // 创建任务栏图标 136 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 137 | taskbarIcon = (TaskbarIcon)FindResource("Taskbar"); 138 | 139 | // 根据用户配置, 设置开机启动 140 | AutoStart.SetAutoStart("妙剪记", "妙剪记", UserConfig.Default.config.isAutoStart); 141 | 142 | // 根据用户配置, 显示设置窗口 143 | if (!UserConfig.Default.config.isStartMinimize) 144 | SharedInstance.ShowSettingWindow(); 145 | 146 | #region App异常监听 147 | 148 | // 主线程异常 149 | DispatcherUnhandledException += App_DispatcherUnhandledException; 150 | //Task异常 151 | TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; 152 | //非UI线程未捕获异常处理事件(例如自己创建的一个子线程) 153 | AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 154 | 155 | #endregion 156 | } 157 | 158 | private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 159 | { 160 | try 161 | { 162 | if (e.ExceptionObject is not Exception exception) return; 163 | // 处理未处理的异常 164 | //SharedInstance.ShowAlert($"发生未处理的异常:{sender}\n{exception}"); 165 | exception.Message.Log(); 166 | if (exception is TypeInitializationException initializationException) initializationException.InnerException?.Message.Log(); 167 | } 168 | catch (Exception) 169 | { 170 | // ignored 171 | } 172 | } 173 | 174 | private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) 175 | { 176 | // 处理未处理的异常 177 | //SharedInstance.ShowAlert($"发生未处理的异常:{sender}\n{e.Exception.Message}"); 178 | e.Exception.Message.Log(); 179 | e.SetObserved(); 180 | } 181 | 182 | private static void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) 183 | { 184 | // 处理未处理的异常 185 | //SharedInstance.ShowAlert($"发生未处理的异常:{sender}\n{e.Exception.Message}"); 186 | // 可以选择标记异常已处理,以阻止应用程序崩溃 187 | 188 | e.Exception.Message.Log(); 189 | // if (e.Exception is TypeInitializationException) 190 | // { 191 | // (e.Exception as TypeInitializationException).InnerException.Message.Log(); 192 | // (e.Exception as TypeInitializationException).StackTrace.Log(); 193 | // (e.Exception as TypeInitializationException).Source.Log(); 194 | // (e.Exception as TypeInitializationException).Message.Log(); 195 | // } 196 | #if DEBUG 197 | e.Handled = false; 198 | #else 199 | e.Handled = true; 200 | #endif 201 | } 202 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:AssemblyInfo.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/8/15 12:17:56 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System.Windows; 10 | 11 | 12 | [assembly: ThemeInfo( 13 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 14 | //(used if a resource is not found in the page, 15 | // or application resource dictionaries) 16 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 17 | //(used if a resource is not found in the page, 18 | // app, or any theme specific resource dictionaries) 19 | )] -------------------------------------------------------------------------------- /MMClipboard.Desktop/CustomUI/Styles/UIButtonStyles.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 49 | 50 | 78 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/CustomUI/Styles/UIToggleButtonStyles.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 112 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/CustomUI/Styles/UIToolTipStyles.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 38 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/CustomUI/UIToggleButton.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:UIToggleButton.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/12/11 15:02:13 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | using System.Windows.Media; 11 | 12 | namespace HtUIKit 13 | { 14 | public class UIToggleButton : CheckBox 15 | { 16 | static UIToggleButton() 17 | { 18 | DefaultStyleKeyProperty.OverrideMetadata(typeof(UIToggleButton), 19 | new FrameworkPropertyMetadata(typeof(UIToggleButton))); 20 | } 21 | 22 | public static readonly DependencyProperty OffTextProperty = 23 | DependencyProperty.Register("OffText", typeof(string), typeof(UIToggleButton), 24 | new PropertyMetadata("关")); 25 | public string OffText 26 | { 27 | get { return (string)GetValue(OffTextProperty); } 28 | set { SetValue(OffTextProperty, value); } 29 | } 30 | 31 | public static readonly DependencyProperty OnTextProperty = 32 | DependencyProperty.Register("OnText", typeof(string), typeof(UIToggleButton), 33 | new PropertyMetadata("开")); 34 | public string OnText 35 | { 36 | get { return (string)GetValue(OnTextProperty); } 37 | set { SetValue(OnTextProperty, value); } 38 | } 39 | 40 | public static readonly DependencyProperty OnForegroundProperty = 41 | DependencyProperty.Register("OnForeground", typeof(Brush), typeof(UIToggleButton), 42 | new PropertyMetadata(Brushes.Silver)); 43 | public Brush OnForeground 44 | { 45 | get { return (Brush)GetValue(OnForegroundProperty); } 46 | set { SetValue(OnForegroundProperty, value); } 47 | } 48 | 49 | public static readonly DependencyProperty OnBackgroundProperty = 50 | DependencyProperty.Register("OnBackground", typeof(Brush), typeof(UIToggleButton), 51 | new PropertyMetadata(Brushes.Green)); 52 | public Brush OnBackground 53 | { 54 | get { return (Brush)GetValue(OnBackgroundProperty); } 55 | set { SetValue(OnBackgroundProperty, value); } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Dictionary/StaticFonts.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | JetBrains Mono Light 12 | 13 | 14 | 15 | JetBrains Mono Regular 16 | 17 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/Dictionary/StaticSolidColors.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 14 | 15 | 16 | 18 | 19 | 21 | 23 | 25 | 27 | 29 | 30 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/Font/JetBrainsMono-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Font/JetBrainsMono-Light.ttf -------------------------------------------------------------------------------- /MMClipboard.Desktop/Font/JetBrainsMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Font/JetBrainsMono-Regular.ttf -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/Add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/Add.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/AppMainPage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/AppMainPage.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/Calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/Calendar.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/Close1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/Close1.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/Collected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/Collected.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/DefaultBg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/DefaultBg.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/DirectoryDefaultLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/DirectoryDefaultLogo.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/Exe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/Exe.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/FileDefaultLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/FileDefaultLogo.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/FileIcons/文件夹.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/FileIcons/文件夹.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/IconPng.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/IconPng.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/ItemMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/ItemMenu.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/Logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/Logo.ico -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/Search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/Search.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/SettingImg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/SettingImg.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/TaskbarIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/TaskbarIcon.ico -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/close.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/defaultImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/defaultImage.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/delete.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/edit.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/Images/noCollect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.Desktop/Images/noCollect.png -------------------------------------------------------------------------------- /MMClipboard.Desktop/MMClipboard.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net8.0-windows10.0.17763.0 6 | disable 7 | true 8 | True 9 | Ht 10 | StartUp 11 | 妙剪记 12 | com.Ht.MMClipborder 13 | MMClipboard 14 | Images\Logo.ico 15 | zh-CN 16 | 1.24.227.1 17 | 1.24.227.1 18 | 1.24.227.1 19 | © 2024 Ht. All rights reserved. 20 | AnyCPU 21 | False 22 | 23 | 24 | 25 | 1701;1702,CS8618,CS8604,CS0067,CS8622,CS8981 26 | True 27 | embedded 28 | True 29 | 30 | 31 | 32 | 1701;1702,CS8618,CS8604,CS0067,CS8622,CS8981 33 | True 34 | embedded 35 | True 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | Never 99 | 100 | 101 | Never 102 | 103 | 104 | Never 105 | 106 | 107 | Never 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/MMClipboard.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | <_LastSelectedProfileId>F:\WPFProjects\MMClipboard\MMClipboard.Desktop\Properties\PublishProfiles\FolderProfile.pubxml 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/MMClipboard.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34024.191 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MMClipboard", "MMClipboard.csproj", "{819F5319-F737-49FD-8390-757FCD48D9D5}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtKit", "HtKit\HtKit.csproj", "{9B3D5C9A-CA24-4DA9-B1F4-6D8B65F1F172}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {819F5319-F737-49FD-8390-757FCD48D9D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {819F5319-F737-49FD-8390-757FCD48D9D5}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {819F5319-F737-49FD-8390-757FCD48D9D5}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {819F5319-F737-49FD-8390-757FCD48D9D5}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {9B3D5C9A-CA24-4DA9-B1F4-6D8B65F1F172}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {9B3D5C9A-CA24-4DA9-B1F4-6D8B65F1F172}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {9B3D5C9A-CA24-4DA9-B1F4-6D8B65F1F172}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {9B3D5C9A-CA24-4DA9-B1F4-6D8B65F1F172}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {AC64155F-186D-4108-99CC-9A46E77B9C96} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/Model/ShortcutPhraseModel.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:ShortcutPhraseModel.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2024-02-03 15:35:29 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using CommunityToolkit.Mvvm.ComponentModel; 10 | using FreeSql.DataAnnotations; 11 | using MMClipboard.Tool; 12 | 13 | 14 | namespace MMClipboard.Model; 15 | 16 | [Table(Name = "phrase")] 17 | public class ShortcutPhraseModel : ObservableObject 18 | { 19 | [Column(IsIdentity = true)] public int id { get; set; } 20 | 21 | /// 22 | /// 短语标题,默认为内容 23 | /// 24 | public string title { get; set; } = ""; 25 | 26 | /// 27 | /// 短语内容 28 | /// 29 | [Column(StringLength = 1000)] 30 | public string phrase { get; set; } = ""; 31 | 32 | /// 33 | /// 标签颜色 默认红色 34 | /// 35 | public string tagColor { get; set; } = "FF0000"; 36 | 37 | /// 38 | /// 标签名称 39 | /// 40 | public string tagName { get; set; } = "默认分组"; 41 | 42 | private ShortcutPhraseModel() 43 | { } 44 | 45 | public static ShortcutPhraseModel Create(string phrase, string tagName = null, string title = null, string tagColor = null) 46 | { 47 | var res = new ShortcutPhraseModel() 48 | { 49 | phrase = phrase, 50 | title = title ?? phrase 51 | }; 52 | 53 | if (!tagName.Ht_IsEmpty()) 54 | res.tagName = tagName; 55 | 56 | if (tagColor is not null) 57 | { 58 | res.tagColor = tagColor; 59 | } 60 | else 61 | { 62 | var colorStr = DataBaseController.GetPhraseTagColorWithTag(tagName); 63 | res.tagColor = colorStr ?? "FF0000"; 64 | } 65 | return res; 66 | } 67 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | F:\Desktop\MMClipboard 10 | FileSystem 11 | <_TargetId>Folder 12 | net8.0-windows10.0.17763.0 13 | win-x64 14 | true 15 | true 16 | false 17 | false 18 | 19 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/Properties/PublishProfiles/FolderProfile.pubxml.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | True|2024-02-03T07:18:47.4982667Z;True|2024-01-30T17:23:21.2949327+08:00;True|2024-01-30T16:34:13.5858320+08:00;True|2024-01-30T16:31:20.8786627+08:00;True|2024-01-30T16:11:07.3480007+08:00;True|2024-01-30T16:09:32.6038424+08:00;True|2024-01-30T16:03:21.2251476+08:00;True|2024-01-30T14:28:23.7967072+08:00;True|2024-01-30T14:23:52.4048964+08:00;True|2024-01-30T11:25:53.5314986+08:00;True|2024-01-30T11:14:35.7649150+08:00;True|2024-01-29T14:11:55.6323366+08:00;True|2024-01-29T14:11:19.8119919+08:00;True|2024-01-29T13:39:04.4108393+08:00;True|2024-01-29T13:38:38.1398912+08:00;True|2024-01-29T11:53:15.5961575+08:00;True|2024-01-29T11:51:38.4934094+08:00;True|2024-01-29T11:47:23.5657618+08:00;False|2024-01-29T11:47:00.0481419+08:00;True|2024-01-29T11:46:02.5244718+08:00;True|2024-01-29T11:44:02.7204855+08:00;True|2024-01-29T11:42:14.0778876+08:00;True|2024-01-29T11:31:13.6090253+08:00;True|2024-01-29T11:27:23.9861763+08:00;True|2024-01-29T11:25:14.7402639+08:00;False|2024-01-29T11:24:54.1895103+08:00;True|2024-01-29T11:23:32.6188147+08:00;True|2024-01-29T11:02:49.9710752+08:00;True|2024-01-29T11:01:58.0473450+08:00;False|2024-01-29T11:01:26.4692780+08:00;True|2024-01-26T16:59:32.5631781+08:00;True|2024-01-26T16:58:05.1250226+08:00;True|2023-12-28T17:41:27.1313093+08:00;True|2023-12-26T11:32:28.8986887+08:00;True|2023-12-26T11:30:38.8294756+08:00;True|2023-12-22T10:53:21.5614700+08:00;True|2023-12-22T10:39:29.1376789+08:00;True|2023-12-22T10:38:14.3714126+08:00; 4 | 5 | 6 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/SharedInstance.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:SharedInstance.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/9/22 17:31:40 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Windows; 11 | using System.Windows.Input; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using MMClipboard.UserConfigs; 15 | using MMClipboard.View; 16 | 17 | 18 | namespace MMClipboard; 19 | 20 | public delegate void WindowBackgroundColorChangeDelegate(SolidColorBrush color); 21 | 22 | public delegate void WindowBackgroundImgChangeDelegate(BitmapSource img); 23 | 24 | public delegate void WindowBackgroundChangeDelegate(bool use); 25 | 26 | public sealed class SharedInstance 27 | { 28 | private static volatile SharedInstance instance; 29 | private static readonly object lockObj = new(); 30 | 31 | public WindowBackgroundChangeDelegate backgroundChangeDelegate; 32 | public WindowBackgroundColorChangeDelegate backgroundColorChangeDelegate; 33 | public WindowBackgroundImgChangeDelegate backgroundImageChangeDelegate; 34 | 35 | /// 36 | /// 是否是自身复制的 37 | /// 38 | public bool isCopyFromSelf = false; 39 | 40 | /// 41 | /// 是否需要更新 42 | /// 43 | public bool isNeedUpdate = false; 44 | 45 | /// 46 | /// 是否正在录制快捷键 47 | /// 48 | public bool isRecordingShortcutKey = false; 49 | 50 | /// 51 | /// 主窗口 52 | /// 53 | public Window mainWindow; 54 | 55 | /// 56 | /// 常用短语窗口 57 | /// 58 | public Window phraseWindow; 59 | 60 | /// 61 | /// 自定义的快捷键 62 | /// 63 | public Action registerHotKeyAction; 64 | 65 | /// 66 | /// 通知主窗口刷新数据 67 | /// 68 | public Action reloadDataAction; 69 | 70 | /// 71 | /// 新增常用短语消息 72 | /// 73 | public Action addPhraseAction; 74 | 75 | /// 76 | /// 搜索窗口 77 | /// 78 | public ContentInputWindow contentInputWindow; 79 | 80 | /// 81 | /// 设置窗口 82 | /// 83 | public SettingWindow settingWindow; 84 | 85 | private SharedInstance() 86 | { } 87 | 88 | public static SharedInstance Instance 89 | { 90 | get 91 | { 92 | if (instance == null) 93 | lock (lockObj) 94 | { 95 | if (null == instance) instance = new SharedInstance(); 96 | } 97 | 98 | return instance; 99 | } 100 | } 101 | 102 | public static void Reset() 103 | { 104 | instance = null; 105 | } 106 | 107 | /// 108 | /// 显示主窗口 109 | /// 110 | public static void ShowMainWindow() 111 | { 112 | if (Instance.mainWindow != null) 113 | { 114 | Instance.mainWindow.Close(); 115 | return; 116 | } 117 | if (UserConfig.Default.config.isSmall) 118 | ShowSmallW(); 119 | else 120 | ShowMainW(); 121 | } 122 | 123 | private static void ShowMainW() 124 | { 125 | MainWindow mw = new(); 126 | Instance.mainWindow = mw; 127 | mw.Show(); 128 | } 129 | 130 | private static void ShowSmallW() 131 | { 132 | SmallWindow sw = new(); 133 | Instance.mainWindow = sw; 134 | sw.Show(); 135 | } 136 | 137 | /// 138 | /// 显示短语窗口 139 | /// 140 | public static void ShowPhraseWindow() 141 | { 142 | Instance.phraseWindow?.Close(); 143 | ShortcutPhraseWindow sw = new(); 144 | Instance.phraseWindow = sw; 145 | sw.Show(); 146 | } 147 | 148 | /// 149 | /// 显示设置窗口 150 | /// 151 | public static void ShowSettingWindow(Window owner = null) 152 | { 153 | if (Instance.settingWindow is null) 154 | { 155 | SettingWindow settingWindow = new(); 156 | if (owner != null) 157 | { 158 | settingWindow.Owner = owner; 159 | settingWindow.ShowDialog(); 160 | return; 161 | } 162 | settingWindow.Show(); 163 | } 164 | else 165 | { 166 | Instance.settingWindow.Topmost = true; 167 | Instance.settingWindow.WindowState = WindowState.Normal; 168 | Instance.settingWindow.Activate(); 169 | } 170 | } 171 | 172 | /// 173 | /// 在需要时切换显示窗口的类型 174 | /// 175 | /// 176 | public static void ChangeWindow(bool isSmall) 177 | { 178 | Instance.mainWindow?.Close(); 179 | if (isSmall) 180 | ShowSmallW(); 181 | else 182 | ShowMainW(); 183 | } 184 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/StartUp.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:StartUp.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/9/22 11:49:40 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using MMClipboard; 11 | 12 | 13 | public class StartUp 14 | { 15 | [STAThread()] 16 | private static void Main() 17 | { 18 | App app = new(); 19 | app.InitializeComponent(); 20 | app.Run(); 21 | } 22 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Style/CollectToggleButtonStyle.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 31 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/Style/ContextMenuStyle.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 36 | 37 | 38 | 119 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/Style/PageStyle.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 44 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/Style/SearchTextBoxStyle.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/Style/TextBlockStyles.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 16 | 21 | 22 | 27 | 32 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/Tool/AppUpdate/AppUpdateManager.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:AppUpdateManager.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/12/15 17:31:24 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Threading.Tasks; 11 | using System.Windows; 12 | using HtKit; 13 | using HtKit.NetWorking; 14 | using MMClipboard.UserConfigs; 15 | using Newtonsoft.Json; 16 | 17 | 18 | namespace MMClipboard.Tool.AppUpdate; 19 | 20 | public abstract class AppUpdateManager 21 | { 22 | public static async void Check(Action ac) 23 | { 24 | var localV = ReadLocalVersionNo(); 25 | Version local = new(localV); 26 | Version remote; 27 | await Task.Run(() => 28 | { 29 | GetVersionInfo((mod) => 30 | { 31 | remote = new Version(mod.version); 32 | var result = local.CompareTo(remote); 33 | if (result < 0) 34 | { 35 | "需要更新".Debug(); 36 | Dispatch.BackToMainThreadAsync(() => ac?.Invoke(true, mod)); 37 | } 38 | else 39 | { 40 | "不需要更新".Debug(); 41 | Dispatch.BackToMainThreadAsync(() => ac?.Invoke(false, mod)); 42 | } 43 | }); 44 | }); 45 | } 46 | 47 | private static void GetVersionInfo(Action action) 48 | { 49 | var url = UserConfig.Default.config.updatePlace == 0 50 | ? "https://raw.githubusercontent.com/ProjectLion/MMClipboard/main/VersionInfo.json" 51 | : "https://gitee.com/HtReturnTrue/MMClipboard/raw/main/VersionInfo.json"; 52 | NetHelper.GetResponse(url, (data) => 53 | { 54 | action?.Invoke(JsonConvert.DeserializeObject(data)); 55 | }, (err) => 56 | { 57 | err.Log(); 58 | }); 59 | } 60 | 61 | public static string ReadLocalVersionNo() 62 | { 63 | var version = Application.ResourceAssembly.GetName().Version; 64 | return version is null ? "1.0.0.0" : version.ToString(4); 65 | } 66 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Tool/AppUpdate/VersionModel.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:VersionModel.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/12/15 17:32:43 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | namespace MMClipboard.Tool.AppUpdate; 10 | 11 | public class VersionModel 12 | { 13 | /// 14 | /// 版本号 15 | /// 16 | public string version { get; set; } = "1.0.0"; 17 | 18 | /// 19 | /// 更新说明 20 | /// 21 | public string updateMsg { get; set; } = ""; 22 | 23 | /// 24 | /// 下载地址 25 | /// 26 | public string updateUrl_GitHub { get; set; } = ""; 27 | 28 | /// 29 | /// 下载地址 30 | /// 31 | public string updateUrl_Gitee { get; set; } = ""; 32 | 33 | /// 34 | /// 更新时间 35 | /// 36 | public string updateTime { get; set; } = "2023-12-12"; 37 | 38 | /// 39 | /// 文件大小 40 | /// 41 | public long fileSize { get; set; } = 0; 42 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Tool/BindingConverter/HistoryItemDataConverters.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:HistoryItemDataConverters.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/9/18 09:07:56 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Globalization; 11 | using System.IO; 12 | using System.Windows; 13 | using System.Windows.Data; 14 | using System.Windows.Media; 15 | using System.Windows.Media.Imaging; 16 | using HtKit; 17 | 18 | 19 | namespace MMClipboard.Tool.BindingConverter; 20 | 21 | #region 文本类型的文字裁剪,优化RichTextBox的显示性能,多余的字没必要显示 22 | 23 | public class HistoryItemTextCutConverter : IValueConverter 24 | { 25 | object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) 26 | { 27 | var tep = value?.ToString(); 28 | if (tep is null) 29 | return ""; 30 | return tep.Length > 300 ? tep[..299] : tep; 31 | } 32 | 33 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 34 | { 35 | throw new NotImplementedException(); 36 | } 37 | } 38 | 39 | #endregion 根据类型的不同切换背景色 40 | 41 | #region 根据类型的不同切换背景色 42 | 43 | public class HistoryItemBackgroundColorConverter : IValueConverter 44 | { 45 | object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) 46 | { 47 | if (value == null) 48 | return (SolidColorBrush)Application.Current.FindResource("筛选按钮.Text"); 49 | return (ClipType)value switch 50 | { 51 | ClipType.Text => (SolidColorBrush)Application.Current.FindResource("筛选按钮.Text"), 52 | ClipType.Image => (SolidColorBrush)Application.Current.FindResource("筛选按钮.Image"), 53 | ClipType.File => (SolidColorBrush)Application.Current.FindResource("筛选按钮.File"), 54 | _ => (SolidColorBrush)Application.Current.FindResource("筛选按钮.Text") 55 | }; 56 | } 57 | 58 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 59 | { 60 | throw new NotImplementedException(); 61 | } 62 | } 63 | 64 | #endregion 根据类型的不同切换背景色 65 | 66 | #region 根据类型显示不同的控件 67 | 68 | public class HistoryItemShowTextConverter : IValueConverter 69 | { 70 | object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) 71 | { 72 | if (value == null) 73 | return Visibility.Collapsed; 74 | return (ClipType)value == ClipType.Text ? Visibility.Visible : Visibility.Collapsed; 75 | } 76 | 77 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 78 | { 79 | throw new NotImplementedException(); 80 | } 81 | } 82 | 83 | public class HistoryItemShowImageConverter : IValueConverter 84 | { 85 | object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) 86 | { 87 | if (value == null) 88 | return Visibility.Collapsed; 89 | return (ClipType)value == ClipType.Image ? Visibility.Visible : Visibility.Collapsed; 90 | } 91 | 92 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 93 | { 94 | throw new NotImplementedException(); 95 | } 96 | } 97 | 98 | public class HistoryItemShowFileConverter : IValueConverter 99 | { 100 | object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) 101 | { 102 | if (value == null) 103 | return Visibility.Collapsed; 104 | return (ClipType)value == ClipType.File ? Visibility.Visible : Visibility.Collapsed; 105 | } 106 | 107 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 108 | { 109 | throw new NotImplementedException(); 110 | } 111 | } 112 | 113 | #endregion 根据类型显示不同的控件 114 | 115 | #region 复制的文件(夹)名 116 | 117 | public class HistoryItemFileNameConverter : IValueConverter 118 | { 119 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 120 | { 121 | if (value == null || string.IsNullOrEmpty(value.ToString())) 122 | return null; 123 | var path = value.ToString(); 124 | if (File.Exists(path)) 125 | return Path.GetFileName(path); 126 | return Directory.Exists(path) ? Path.GetFileName(path) : "文件(夹)不存在"; 127 | } 128 | 129 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 130 | { 131 | throw new NotImplementedException(); 132 | } 133 | } 134 | 135 | #endregion 复制的文件Logo 136 | 137 | #region 收藏状态 138 | 139 | public class HistoryItemCollectStateConverter : IValueConverter 140 | { 141 | object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) 142 | { 143 | var url = "/Images/noCollect.png"; 144 | if (value != null) 145 | url = value.ToString() == "1" ? "/Images/Collected.png" : "/Images/noCollect.png"; 146 | return new BitmapImage(new Uri(url, UriKind.Relative)); 147 | } 148 | 149 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 150 | { 151 | throw new NotImplementedException(); 152 | } 153 | } 154 | 155 | public class HistoryItemCollectStateBgColorConverter : IValueConverter 156 | { 157 | object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) 158 | { 159 | var colorStr = "#00673AB7"; 160 | if (value != null && value.ToString() == "1") 161 | colorStr = "#FF673AB7"; 162 | return HtColor.GetBrushWithString(colorStr); 163 | } 164 | 165 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 166 | { 167 | throw new NotImplementedException(); 168 | } 169 | } 170 | 171 | #endregion -------------------------------------------------------------------------------- /MMClipboard.Desktop/Tool/BindingConverter/NodataTipHideConverter.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:NodataTipHideConverter.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/12/18 12:17:56 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Collections; 11 | using System.Globalization; 12 | using System.Windows; 13 | using System.Windows.Data; 14 | 15 | 16 | namespace MMClipboard.Tool.BindingConverter; 17 | 18 | public class NodataTipHideConverter : IValueConverter 19 | { 20 | object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) 21 | { 22 | if (value == null || ((ICollection)value).Count <= 0) 23 | return Visibility.Visible; 24 | return Visibility.Collapsed; 25 | } 26 | 27 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 28 | { 29 | throw new NotImplementedException(); 30 | } 31 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Tool/BindingConverter/PhraseItemDataConverters.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:PhraseItemDataConverters.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2024-02-04 16:52:49 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Globalization; 11 | using System.Windows.Data; 12 | using HtKit; 13 | 14 | 15 | namespace MMClipboard.Tool.BindingConverter; 16 | 17 | public class PhraseGroupColorConverter : IValueConverter 18 | { 19 | object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) 20 | { 21 | if (value == null || ((string)value).Ht_IsEmpty()) 22 | return HtColor.GetBrushWithString("#FFFFFF"); 23 | return HtColor.GetBrushWithString($"#{value}"); 24 | } 25 | 26 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 27 | { 28 | throw new NotImplementedException(); 29 | } 30 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Tool/BindingConverter/SettingPageConverter.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:SettingPageConverter.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/12/11 17:19:11 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | using System; 9 | using System.Globalization; 10 | using System.Windows; 11 | using System.Windows.Data; 12 | 13 | namespace MMClipboard.Tool.BindingConverter 14 | { 15 | public class ChooseBGImgVisibilityConverter : IValueConverter 16 | { 17 | object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) 18 | { 19 | if (value == null) 20 | return Visibility.Collapsed; 21 | if ((bool)value) 22 | return Visibility.Visible; 23 | else 24 | return Visibility.Collapsed; 25 | } 26 | 27 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 28 | { 29 | throw new NotImplementedException(); 30 | } 31 | } 32 | 33 | public class ChooseBGColorVisibilityConverter : IValueConverter 34 | { 35 | object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) 36 | { 37 | if (value == null) 38 | return Visibility.Collapsed; 39 | if ((bool)value) 40 | return Visibility.Collapsed; 41 | else 42 | return Visibility.Visible; 43 | } 44 | 45 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 46 | { 47 | throw new NotImplementedException(); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Tool/CacheHelper.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:CacheHelper.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/12/7 17:08:35 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.IO; 11 | using System.Threading.Tasks; 12 | using System.Windows; 13 | using System.Windows.Media; 14 | using System.Windows.Media.Imaging; 15 | using HtKit; 16 | 17 | 18 | namespace MMClipboard.Tool; 19 | 20 | public static class CacheHelper 21 | { 22 | private static string CacheDir(DateTime date) 23 | { 24 | var dp = Path.Combine(AppPath.GetBaseDirectory(), $"Cache\\{date:yyyyMMdd}"); 25 | if (!Directory.Exists(dp)) 26 | Directory.CreateDirectory(dp); 27 | return dp; 28 | } 29 | 30 | private static string GetCacheImagePath(DateTime date) 31 | { 32 | var dp = Path.Combine(AppPath.GetBaseDirectory(), $"Cache\\{date:yyyyMMdd}"); 33 | if (!Directory.Exists(dp)) 34 | Directory.CreateDirectory(dp); 35 | var timestamp = (long)(date - new DateTime(1970, 1, 1)).TotalMilliseconds; 36 | var dbFilePath = Path.Combine(dp, $"mm_{timestamp}.png"); 37 | return dbFilePath; 38 | } 39 | 40 | /// 41 | /// 复制文件 42 | /// Copy file 43 | /// 44 | /// 45 | /// 46 | /// 47 | public static string CopyFile(string originFilePath, DateTime date) 48 | { 49 | var fileName = Path.GetFileName(originFilePath); 50 | var cacheP = Path.Combine(AppPath.GetBaseDirectory(), $"{CacheDir(date)}\\{fileName}"); 51 | if (File.Exists(cacheP)) 52 | return cacheP; 53 | try 54 | { 55 | File.Copy(originFilePath, cacheP); 56 | // 设置文件权限为可读可写,否则在删除父级文件夹时会报错 57 | File.SetAttributes(cacheP, FileAttributes.Normal); 58 | return cacheP; 59 | } 60 | catch (Exception e) 61 | { 62 | e.Debug(); 63 | return originFilePath; 64 | } 65 | } 66 | 67 | /// 68 | /// 保存图片 69 | /// 70 | /// 71 | /// 72 | public static string SaveImage(BitmapSource bitmap, DateTime date) 73 | { 74 | var p = GetCacheImagePath(date); 75 | var encoder = new BmpBitmapEncoder(); 76 | encoder.Frames.Add(BitmapFrame.Create(bitmap)); 77 | 78 | // 创建一个文件流以保存 PNG 文件 79 | using var stream = new FileStream(p, FileMode.Create); 80 | encoder.Save(stream); 81 | stream.Flush(); 82 | return p; 83 | } 84 | 85 | /// 86 | /// 清空某一天的缓存 87 | /// Clear the cache for a date 88 | /// 89 | /// 90 | public static void ClearCache(DateTime date) 91 | { 92 | try 93 | { 94 | if (date == DateTime.MinValue) 95 | { 96 | Directory.Delete(Path.Combine(AppPath.GetBaseDirectory(), "Cache"), true); 97 | } 98 | else 99 | { 100 | var dp = Path.Combine(AppPath.GetBaseDirectory(), $"Cache\\{date:yyyyMMdd}"); 101 | if (!Directory.Exists(dp)) return; 102 | Directory.Delete(dp, true); 103 | } 104 | } 105 | catch (Exception e) 106 | { 107 | e.Message.Log(); 108 | } 109 | } 110 | 111 | /// 112 | /// 删除缓存图片 113 | /// 114 | /// 115 | public static void DeleteCacheImage(string path) 116 | { 117 | // 只删除缓存到程序目录下的图片文件,其他的用户的图片文件不能去动 118 | if (!path.Contains(@"Cache\") || !Path.GetFileName(path).Contains("mm_")) 119 | return; 120 | if (!File.Exists(path)) 121 | return; 122 | try 123 | { 124 | File.Delete(path); 125 | } 126 | catch (Exception e) 127 | { 128 | e.Log(); 129 | } 130 | } 131 | 132 | /// 133 | /// 加载本地缓存图片 134 | /// 135 | /// 136 | /// 137 | /// 138 | public static void LoadCacheImage(string path, Action ac) 139 | { 140 | var p = path; 141 | if (!File.Exists(p)) 142 | { 143 | ac?.Invoke(new BitmapImage(new Uri("/Images/defaultImage.png", UriKind.Relative))); 144 | return; 145 | } 146 | Task.Run(() => 147 | { 148 | using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 149 | var buffer = new byte[fileStream.Length]; 150 | _ = fileStream.Read(buffer, 0, (int)fileStream.Length); 151 | fileStream.Flush(); 152 | fileStream.Close(); 153 | LoadImageAsync(buffer, ac); 154 | }); 155 | } 156 | 157 | private static void LoadImageAsync(byte[] buffer, Action ac) 158 | { 159 | // InvokeAsync()方法用于异步执行,防止在UI线程阻塞。 160 | // 不能使用Await,否则会阻塞UI线程。 161 | Application.Current.Dispatcher.InvokeAsync(() => 162 | { 163 | try 164 | { 165 | // 将BitmapImage转换为WriteableBitmap,性能更好了。嘻嘻 166 | // 使用BitmapImage加载有些分辨率高的图片会报错,而WriteableBitmap不会,兼容性更好。嘻嘻 167 | var stream = new MemoryStream(buffer); 168 | var decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.None); 169 | var frame = decoder.Frames[0]; 170 | var formatConverter = new FormatConvertedBitmap(frame, PixelFormats.Bgra32, null, 0); 171 | var writeableBitmap = new WriteableBitmap(formatConverter); 172 | ac?.Invoke(writeableBitmap); 173 | } 174 | catch (Exception e) 175 | { 176 | e.Log(); 177 | ac?.Invoke(new BitmapImage(new Uri("/Images/defaultImage.png", UriKind.Relative))); 178 | } 179 | }); 180 | } 181 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Tool/ClipTypeEnum.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:ClipTypeEnum.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/9/22 10:15:12 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | namespace MMClipboard.Tool; 10 | 11 | public enum ClipType 12 | { 13 | All, 14 | Text, 15 | Image, 16 | File 17 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Tool/ClipboardListener.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:ClipboardListener.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2024-02-25 18:19:38 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Diagnostics; 12 | using System.Linq; 13 | using System.Runtime.InteropServices; 14 | using System.Windows; 15 | using System.Windows.Interop; 16 | using HtKit; 17 | using MMClipboard.Model; 18 | 19 | 20 | namespace MMClipboard.Tool; 21 | 22 | public static class ClipboardListener 23 | { 24 | internal static readonly IntPtr HwndMessage = -3; 25 | 26 | // 将窗口添加到剪贴板格式侦听器列表. 27 | // 微软文档:每当剪贴板的内容发生更改时,该窗口将发布 WM_CLIPBOARDUPDATE: 0x031D 消息。 28 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 29 | private static extern bool AddClipboardFormatListener(IntPtr hWnd); 30 | 31 | // 从系统维护的剪贴板格式侦听器列表中删除给定窗口。 32 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 33 | private static extern bool RemoveClipboardFormatListener(IntPtr hWnd); 34 | 35 | private static HwndSource source; 36 | 37 | private static string oldClipContent; 38 | 39 | public static void Add() 40 | { 41 | var parameters = new HwndSourceParameters("mmclipboard hook") 42 | { 43 | HwndSourceHook = HwndHook, 44 | ParentWindow = HwndMessage 45 | }; 46 | source ??= new HwndSource(parameters); 47 | if (AddClipboardFormatListener(source.Handle)) 48 | "剪切板监听成功".Log(); 49 | source.AddHook(HwndHook); 50 | } 51 | 52 | public static void Remove() 53 | { 54 | RemoveClipboardFormatListener(source.Handle); 55 | } 56 | 57 | private static IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 58 | { 59 | const int WM_CLIPBOARDUPDATE = 0x031D; 60 | switch (msg) 61 | { 62 | case WM_CLIPBOARDUPDATE: 63 | // 剪切板内容变化,微软文档中说,这个消息在剪切板内容变化时发送 64 | "剪切板内容变化,微软文档中说,这个消息在剪切板内容变化时发送".Debug(); 65 | ClipboardContentChanged(); 66 | break; 67 | } 68 | return IntPtr.Zero; 69 | } 70 | 71 | private static void ClipboardContentChanged() 72 | { 73 | // 如果是当前App做的复制粘贴操作则不复制。 74 | if (SharedInstance.Instance.isCopyFromSelf) 75 | return; 76 | try 77 | { 78 | var hWnd = Win32Api.GetForegroundWindow(); //获取活动窗口句柄 79 | _ = Win32Api.GetWindowThreadProcessId(hWnd, out var calcID); 80 | using var clipProcess = Process.GetProcessById(calcID); 81 | if (Clipboard.ContainsText()) 82 | SaveText(clipProcess); 83 | else if (Clipboard.ContainsFileDropList()) 84 | SaveFile(clipProcess); 85 | else if (Clipboard.ContainsImage()) 86 | SaveImage(clipProcess); 87 | SharedInstance.Instance.isCopyFromSelf = false; 88 | } 89 | catch (Exception e) 90 | { 91 | e.Message.Debug(); 92 | } 93 | } 94 | 95 | /// 96 | /// 保存文本 97 | /// 98 | /// 99 | private static void SaveText(Process clipProcess) 100 | { 101 | /* 102 | UnicodeText = 1, 103 | Rtf = 2, 104 | Html = 3, 105 | CommaSeparatedValue = 4, 106 | Xaml = 5 107 | */ 108 | var text = Clipboard.GetText(TextDataFormat.UnicodeText); 109 | if (oldClipContent == text) 110 | return; 111 | var now = DateTime.Now; 112 | oldClipContent = text; 113 | var mod = new ClipItemModel() 114 | { 115 | from = clipProcess.ProcessName, 116 | fromExeImgPath = clipProcess.MainModule != null ? clipProcess.MainModule.FileName : string.Empty, 117 | date = now, 118 | rtfContent = string.Empty, 119 | clipType = ClipType.Text, 120 | content = text 121 | }; 122 | 123 | // win11的资源管理器右键复制的文件地址会被双引号包着,将引号去掉 124 | if (clipProcess.ProcessName == "explorer" && text.First() == '"' && text.Last() == '"') 125 | mod.content = text.Trim('"'); 126 | 127 | if (Clipboard.ContainsText(TextDataFormat.Rtf)) 128 | { 129 | var rtfText = Clipboard.GetText(TextDataFormat.Rtf); 130 | mod.rtfContent = rtfText; 131 | } 132 | if (DataBaseController.AddHistoryDataFromList([mod])) 133 | SharedInstance.Instance.reloadDataAction?.Invoke(); 134 | } 135 | 136 | /// 137 | /// 保存图片 138 | /// 139 | /// 140 | private static void SaveImage(Process clipProcess) 141 | { 142 | var img = Clipboard.GetImage(); 143 | if (img == null) 144 | return; 145 | var now = DateTime.Now; 146 | // $"W:{img.PixelWidth}, H:{img.PixelHeight}".Debug(); 147 | var mod = new ClipItemModel 148 | { 149 | from = clipProcess.ProcessName, 150 | date = now, 151 | fromExeImgPath = clipProcess.MainModule != null ? clipProcess.MainModule.FileName : string.Empty, 152 | rtfContent = string.Empty, 153 | clipType = ClipType.Image, 154 | content = CacheHelper.SaveImage(img, now) 155 | }; 156 | if (DataBaseController.AddHistoryDataFromList([mod])) 157 | SharedInstance.Instance.reloadDataAction?.Invoke(); 158 | } 159 | 160 | /// 161 | /// 保存文件 162 | /// 163 | /// 164 | private static void SaveFile(Process clipProcess) 165 | { 166 | var files = Clipboard.GetFileDropList().Cast().ToArray(); 167 | var clipContent = ""; 168 | var l = new List(); 169 | var now = DateTime.Now; 170 | foreach (var item in files) 171 | { 172 | var mod = new ClipItemModel() 173 | { 174 | from = clipProcess.ProcessName, 175 | date = now, 176 | fromExeImgPath = clipProcess.MainModule != null ? clipProcess.MainModule.FileName : string.Empty, 177 | rtfContent = string.Empty, 178 | clipType = item.Ht_IsImage() ? ClipType.Image : ClipType.File, 179 | content = item 180 | }; 181 | clipContent += item; 182 | l.Add(mod); 183 | } 184 | if (oldClipContent == clipContent) 185 | return; 186 | if (DataBaseController.AddHistoryDataFromList(l)) 187 | SharedInstance.Instance.reloadDataAction?.Invoke(); 188 | } 189 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Tool/CopyAndPasteHelper.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:CopyAndPasteHelper.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2024-02-03 17:14:04 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Collections.Specialized; 11 | using System.IO; 12 | using System.Threading.Tasks; 13 | using System.Windows.Forms; 14 | using Clipboard = System.Windows.Clipboard; 15 | using TextDataFormat = System.Windows.TextDataFormat; 16 | 17 | 18 | namespace MMClipboard.Tool; 19 | 20 | public static class CopyAndPasteHelper 21 | { 22 | /// 23 | /// 复制并粘贴文本到其他应用 24 | /// 25 | /// 26 | /// 27 | public static void CopyAndPasteText(string content, Action pastedAc = null) 28 | { 29 | Clipboard.Clear(); 30 | Clipboard.Flush(); 31 | SharedInstance.Instance.isCopyFromSelf = true; 32 | try 33 | { 34 | Clipboard.SetText(content, TextDataFormat.UnicodeText); 35 | } 36 | catch (Exception e) 37 | { 38 | e.Log(); 39 | } 40 | PasteToOtherApps(pastedAc); 41 | } 42 | 43 | /// 44 | /// 复制并粘贴文件到其他应用 45 | /// 46 | /// 47 | /// 48 | public static void CopyAndPasteFile(string path, Action pastedAc = null) 49 | { 50 | Clipboard.Clear(); 51 | Clipboard.Flush(); 52 | SharedInstance.Instance.isCopyFromSelf = true; 53 | try 54 | { 55 | if (!File.Exists(path)) 56 | return; 57 | StringCollection sc = [path]; 58 | Clipboard.SetFileDropList(sc); 59 | } 60 | catch (Exception e) 61 | { 62 | e.Debug(); 63 | } 64 | PasteToOtherApps(pastedAc); 65 | } 66 | 67 | /// 68 | /// 模拟Ctrl+V,粘贴内容到其他应用 69 | /// 70 | /// 71 | private static async void PasteToOtherApps(Action pastedAc) 72 | { 73 | await Task.Run(() => 74 | { 75 | SendKeys.SendWait("^v"); 76 | }); 77 | pastedAc?.Invoke(); 78 | SharedInstance.Instance.isCopyFromSelf = false; 79 | } 80 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Tool/HotKeyManager.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:HotKeyManager.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2024-02-25 17:52:40 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System.Windows.Input; 10 | using NHotkey; 11 | using NHotkey.Wpf; 12 | 13 | 14 | namespace MMClipboard.Tool; 15 | 16 | public static class HotKeyManager 17 | { 18 | public static void RegisterHotKey_ShowMainWindow(Key key, ModifierKeys modifierKeys) 19 | { 20 | HotkeyManager.Current.AddOrReplace("com.ht.mmclipboard.showMain", key, modifierKeys, ShowMainAction); 21 | } 22 | 23 | public static void RegisterHotKey_ShowPhraseWindow(Key key, ModifierKeys modifierKeys) 24 | { 25 | HotkeyManager.Current.AddOrReplace("com.ht.mmclipboard.showPhrase", key, modifierKeys, ShowPhraseAction); 26 | } 27 | 28 | private static void ShowMainAction(object sender, HotkeyEventArgs e) 29 | { 30 | if (!SharedInstance.Instance.isRecordingShortcutKey) 31 | SharedInstance.ShowMainWindow(); 32 | } 33 | 34 | private static void ShowPhraseAction(object sender, HotkeyEventArgs e) 35 | { 36 | if (!SharedInstance.Instance.isRecordingShortcutKey) 37 | SharedInstance.ShowPhraseWindow(); 38 | } 39 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Tool/OpenExternalWindowHelper.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:OpenExternalWindowHelper.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2024-02-04 11:14:42 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Diagnostics; 11 | using System.IO; 12 | 13 | 14 | namespace MMClipboard.Tool; 15 | 16 | /// 17 | /// 打开外部窗口的工具类 18 | /// 19 | public static class OpenExternalWindowHelper 20 | { 21 | /// 22 | /// 打开网页 23 | /// 24 | /// 25 | public static void OpenWebsite(string url) 26 | { 27 | try 28 | { 29 | Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true }); 30 | } 31 | catch (Exception e) 32 | { 33 | e.Message.Log(); 34 | } 35 | } 36 | 37 | /// 38 | /// 打开文件夹并选中文件 39 | /// 40 | /// 41 | public static void SelectFileInFolder(string path) 42 | { 43 | if (!File.Exists(path)) 44 | return; 45 | try 46 | { 47 | Process.Start("explorer.exe", $"/select,\"{path}\""); 48 | } 49 | catch (Exception e) 50 | { 51 | e.Message.Log(); 52 | } 53 | } 54 | 55 | /// 56 | /// 打开文件夹 57 | /// 58 | /// 59 | public static void OpenFolder(string path) 60 | { 61 | if (!Directory.Exists(path)) 62 | return; 63 | try 64 | { 65 | Process.Start("explorer.exe", path); 66 | } 67 | catch (Exception e) 68 | { 69 | e.Message.Log(); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/Tool/UIElementHelper.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:UIElementHelper.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2024-02-03 15:45:43 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System.Windows; 10 | using System.Windows.Media; 11 | 12 | 13 | namespace MMClipboard.Tool; 14 | 15 | public static class UIElementHelper 16 | { 17 | /// 18 | /// 查找可视化树中指定类型的子元素 19 | /// 20 | /// 21 | /// 22 | /// 23 | public static T FindVisualChild(DependencyObject obj) where T : DependencyObject 24 | { 25 | if (obj == null) return null; 26 | for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) 27 | { 28 | var child = VisualTreeHelper.GetChild(obj, i); 29 | if (child is T dependencyObject) return dependencyObject; 30 | var childItem = FindVisualChild(child); 31 | if (childItem != null) return childItem; 32 | } 33 | return null; 34 | } 35 | 36 | /// 37 | /// 查找可视化树中指定类型的祖先元素 38 | /// 39 | /// 40 | /// 41 | /// 42 | public static T FindAncestor(DependencyObject current) 43 | where T : DependencyObject 44 | { 45 | do 46 | { 47 | if (current is T ancestor) return ancestor; 48 | current = VisualTreeHelper.GetParent(current); 49 | } 50 | while (current != null); 51 | 52 | return null; 53 | } 54 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/UserConfigs/Config.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:UserConfig.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/12/7 10:23:40 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.IO; 11 | using System.Windows.Input; 12 | using System.Windows.Media.Imaging; 13 | 14 | 15 | namespace MMClipboard.UserConfigs; 16 | 17 | public class Config 18 | { 19 | /// 20 | /// 开机启动 默认true 21 | /// 22 | public bool isAutoStart { get; set; } = true; 23 | 24 | /// 25 | /// 启动后最小化 默认false 26 | /// 27 | public bool isStartMinimize { get; set; } 28 | 29 | /* 30 | 暂时去掉该功能,我觉得这个功能不是那么必要。 31 | /// 32 | /// 在复制文件时是否复制一份备份到程序目录 默认true 33 | /// 34 | public bool isCopyFile { get; set; } = true; 35 | */ 36 | 37 | /// 38 | /// 是否使用小窗口 默认true 39 | /// 40 | public bool isSmall { get; set; } = true; 41 | 42 | /// 43 | /// 复制完成后是否关闭窗口 默认true 44 | /// 45 | public bool isCopiedClose { get; set; } = true; 46 | 47 | /// 48 | /// 页面背景是否使用高斯模糊图片 默认true 49 | /// 50 | public bool isUseBackgroundImg { get; set; } = true; 51 | 52 | /// 53 | /// 页面背景图片 54 | /// 55 | public string pageBackgroundImg { get; set; } = string.Empty; 56 | 57 | /// 58 | /// 页面背景色 默认#181818 59 | /// 60 | public string pageBackgroundColor { get; set; } = "#181818"; 61 | 62 | /// 63 | /// 快捷键 默认Alt+C 64 | /// 65 | public ModifierKeys modifierKeys { get; set; } = ModifierKeys.Alt; 66 | 67 | public Key key { get; set; } = Key.C; 68 | 69 | /// 70 | /// 更新渠道。0:GitHub 1:Gitee。默认为GitHub 71 | /// 72 | public int updatePlace { get; set; } = 0; 73 | 74 | /// 75 | /// 背景图 76 | /// 77 | public BitmapImage bgImgSource 78 | { 79 | get 80 | { 81 | const string filename = "pack://application:,,,/Images/DefaultBg.png"; 82 | var uri = new Uri(filename, UriKind.Absolute); 83 | try 84 | { 85 | if (isUseBackgroundImg && !pageBackgroundImg.Ht_IsEmpty() && File.Exists(pageBackgroundImg)) 86 | { 87 | var image = new BitmapImage(new Uri(pageBackgroundImg, UriKind.Absolute)); 88 | return image; 89 | } 90 | } 91 | catch (Exception e) 92 | { 93 | e.Message.Debug(); 94 | } 95 | var bmp = new BitmapImage(uri); 96 | return bmp; 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/UserConfigs/UserConfig.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:UserConfig.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/12/15 15:35:34 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | using System.IO; 9 | using System.Windows.Input; 10 | using HtKit; 11 | using Newtonsoft.Json; 12 | 13 | namespace MMClipboard.UserConfigs 14 | { 15 | public class UserConfig 16 | { 17 | private static volatile UserConfig defaults; 18 | private static readonly object lockObj = new(); 19 | private UserConfig() 20 | { } 21 | 22 | public static UserConfig Default 23 | { 24 | get 25 | { 26 | if (defaults != null) return defaults; 27 | lock (lockObj) 28 | { 29 | defaults = new UserConfig(); 30 | } 31 | return defaults; 32 | } 33 | } 34 | 35 | public Config config { get; private set; } 36 | 37 | private static string ConfigFilePath 38 | { 39 | get 40 | { 41 | var dp = Path.Combine(AppPath.GetBaseDirectory(), @"Config"); 42 | if (!Directory.Exists(dp)) 43 | Directory.CreateDirectory(dp); 44 | 45 | var fp = Path.Combine(dp, "Config.mm"); 46 | if (File.Exists(fp)) return fp; 47 | File.Create(fp).Close(); 48 | var json = JsonConvert.SerializeObject(new Config() 49 | { 50 | modifierKeys = ModifierKeys.Alt, 51 | key = Key.C 52 | }); 53 | File.WriteAllText(fp, json); 54 | return fp; 55 | } 56 | } 57 | 58 | /// 59 | /// 更新用户配置 60 | /// 61 | public static void SaveConfig() 62 | { 63 | var json = JsonConvert.SerializeObject(Default.config); 64 | File.WriteAllText(ConfigFilePath, json); 65 | } 66 | 67 | /// 68 | /// 读取用户配置 69 | /// 70 | /// 71 | public static void ReadConfig() 72 | { 73 | Default.config = JsonConvert.DeserializeObject(File.ReadAllText(ConfigFilePath)); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/View/AppUpdateWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:AppUpdateWindow.xaml.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Windows; 11 | using System.Windows.Input; 12 | using MMClipboard.Tool.AppUpdate; 13 | using MMClipboard.ViewModel; 14 | 15 | 16 | namespace MMClipboard.View; 17 | 18 | /// 19 | /// AppUpdateWindow.xaml 的交互逻辑 20 | /// 21 | public partial class AppUpdateWindow : Window 22 | { 23 | public AppUpdateWindow(VersionModel mod) 24 | { 25 | InitializeComponent(); 26 | DataContext = new AppUpdateViewModel(this, mod); 27 | } 28 | 29 | private void CloseBtnClick(object sender, RoutedEventArgs e) 30 | { 31 | (DataContext as AppUpdateViewModel)?.Cancel(); 32 | Close(); 33 | } 34 | 35 | private void HeaderMoveAction(object sender, MouseButtonEventArgs e) 36 | { 37 | DragMove(); 38 | } 39 | 40 | protected override void OnClosed(EventArgs e) 41 | { 42 | base.OnClosed(e); 43 | DataContext = null; 44 | } 45 | 46 | private void UpdateBtnClick(object sender, RoutedEventArgs e) 47 | { 48 | (DataContext as AppUpdateViewModel)?.Update(); 49 | } 50 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/View/ContentInputWindow.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 30 | 35 | 36 | 41 | 42 | 43 | 53 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/View/ContentInputWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:ContentInputWindow.xaml.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Windows; 11 | using System.Windows.Input; 12 | 13 | 14 | namespace MMClipboard.View; 15 | 16 | /// 17 | /// ContentInputWindow.xaml 的交互逻辑 18 | /// 19 | public partial class ContentInputWindow 20 | { 21 | public Action confirmAction; 22 | 23 | private bool isSearch; 24 | 25 | public ContentInputWindow(string content, string confirmTitle) 26 | { 27 | InitializeComponent(); 28 | confirmBtn.title = confirmTitle; 29 | contentTextBox.Text = content; 30 | } 31 | 32 | private void Window_Loaded(object sender, RoutedEventArgs e) 33 | { 34 | Activate(); 35 | contentTextBox.SelectAll(); 36 | Keyboard.Focus(contentTextBox); 37 | } 38 | 39 | private void SearchAction(object sender, MouseButtonEventArgs e) 40 | { 41 | confirmAction?.Invoke(contentTextBox.Text); 42 | isSearch = true; 43 | Close(); 44 | } 45 | 46 | protected override void OnClosed(EventArgs e) 47 | { 48 | base.OnClosed(e); 49 | SharedInstance.Instance.contentInputWindow = null; 50 | } 51 | 52 | protected override void OnDeactivated(EventArgs e) 53 | { 54 | base.OnDeactivated(e); 55 | if (!isSearch) Close(); 56 | } 57 | 58 | private void Window_KeyDown(object sender, KeyEventArgs e) 59 | { 60 | // e.Key.Debug(); 61 | if (e.Key != Key.Enter) return; 62 | confirmAction?.Invoke(contentTextBox.Text); 63 | isSearch = true; 64 | Close(); 65 | } 66 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/View/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 30 | 31 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/View/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:MainWindow.xaml.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Windows.Interop; 11 | using HtKit; 12 | using MMClipboard.ViewModel; 13 | 14 | 15 | namespace MMClipboard.View; 16 | 17 | /// 18 | /// Interaction logic for MainWindow.xaml 19 | /// 20 | public partial class MainWindow 21 | { 22 | public MainWindow() 23 | { 24 | InitializeComponent(); 25 | DataContext = new MainViewModel(this); 26 | } 27 | 28 | protected override void OnSourceInitialized(EventArgs e) 29 | { 30 | base.OnSourceInitialized(e); 31 | const int WS_EX_NOACTIVATE = 0x08000000; 32 | const int WS_CHILD = 0x40000000; 33 | // Get this window's handle 34 | var hWnd = new WindowInteropHelper(this).Handle; 35 | var exStyle = Win32Api.GetWindowLong(hWnd, Win32Api.GWL_EXSTYLE); 36 | exStyle |= 128; 37 | exStyle |= WS_CHILD; 38 | exStyle |= WS_EX_NOACTIVATE; 39 | Win32Api.SetWindowLong(hWnd, Win32Api.GWL_EXSTYLE, exStyle); 40 | } 41 | 42 | protected override void OnClosed(EventArgs e) 43 | { 44 | base.OnClosed(e); 45 | DataContext = null; 46 | SharedInstance.Instance.mainWindow = null; 47 | SharedInstance.Instance.reloadDataAction = null; 48 | MemoryHelper.FlushMemory(); 49 | } 50 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/View/SearchWindow.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 30 | 35 | 36 | 41 | 42 | 43 | 57 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /MMClipboard.Desktop/View/SearchWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:SearchWindow.xaml.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023-12-22 10:01:45 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Windows; 11 | using System.Windows.Input; 12 | 13 | 14 | namespace MMClipboard.View; 15 | 16 | /// 17 | /// SearchWindow.xaml 的交互逻辑 18 | /// 19 | public partial class SearchWindow : Window 20 | { 21 | public Action searchAction; 22 | 23 | private bool isSearch = false; 24 | 25 | public SearchWindow() 26 | { 27 | InitializeComponent(); 28 | } 29 | 30 | private void Window_Loaded(object sender, RoutedEventArgs e) 31 | { 32 | Activate(); 33 | searchTextBox.SelectAll(); 34 | Keyboard.Focus(searchTextBox); 35 | } 36 | 37 | private void SearchAction(object sender, MouseButtonEventArgs e) 38 | { 39 | searchAction?.Invoke(searchTextBox.Text); 40 | isSearch = true; 41 | Close(); 42 | } 43 | 44 | protected override void OnClosed(EventArgs e) 45 | { 46 | base.OnClosed(e); 47 | } 48 | 49 | protected override void OnDeactivated(EventArgs e) 50 | { 51 | base.OnDeactivated(e); 52 | if (!isSearch) Close(); 53 | } 54 | 55 | private void Window_KeyDown(object sender, KeyEventArgs e) 56 | { 57 | if (e.Key != Key.Enter) return; 58 | searchAction?.Invoke(searchTextBox.Text); 59 | isSearch = true; 60 | Close(); 61 | } 62 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/View/SettingWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:SettingWindow.xaml.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/12/18 12:17:56 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Diagnostics; 11 | using System.Text; 12 | using System.Windows; 13 | using System.Windows.Input; 14 | using HtKit; 15 | using HtUIKit; 16 | using MMClipboard.UserConfigs; 17 | using MMClipboard.ViewModel; 18 | 19 | 20 | namespace MMClipboard.View; 21 | 22 | /// 23 | /// SettingWindow.xaml 的交互逻辑 24 | /// 25 | public partial class SettingWindow 26 | { 27 | public SettingWindow() 28 | { 29 | InitializeComponent(); 30 | DataContext = new SettingViewModel(); 31 | SharedInstance.Instance.settingWindow = this; 32 | updatePlaceText.Text = UserConfig.Default.config.updatePlace == 0 ? "GitHub" : "Gitee"; 33 | } 34 | 35 | protected override void OnClosed(EventArgs e) 36 | { 37 | base.OnClosed(e); 38 | DataContext = null; 39 | SharedInstance.Instance.settingWindow = null; 40 | } 41 | 42 | /// 43 | /// 关闭窗口 44 | /// Close the window 45 | /// 46 | /// 47 | /// 48 | private void CloseAction(object sender, RoutedEventArgs e) 49 | { 50 | Close(); 51 | e.Handled = true; 52 | } 53 | 54 | /// 55 | /// 打开GitHub页面 56 | /// Open GitHub page 57 | /// 58 | /// 59 | /// 60 | private void OpenGitHubPageAction(object sender, RoutedEventArgs e) 61 | { 62 | try 63 | { 64 | Process.Start("explorer.exe", "https://github.com/ProjectLion/MMClipboard"); 65 | } 66 | catch (Exception ex) 67 | { 68 | ex.Log(); 69 | } 70 | } 71 | 72 | /// 73 | /// 窗口移动 74 | /// The window moves 75 | /// 76 | /// 77 | /// 78 | private void HeaderMoveAction(object sender, MouseButtonEventArgs e) 79 | { 80 | DragMove(); 81 | } 82 | 83 | /// 84 | /// 选择背景颜色 85 | /// Select a background color 86 | /// 87 | private void ChooseBGColorAction(object sender, MouseButtonEventArgs e) 88 | { 89 | colorPopup.IsOpen = true; 90 | e.Handled = true; 91 | } 92 | 93 | /// 94 | /// 选择背景图片 95 | /// Select a background image 96 | /// 97 | /// 98 | /// 99 | private void chooseBGImageBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 100 | { 101 | ChooseFileManager.SelectImageFile((fileP) => 102 | { 103 | if (string.IsNullOrEmpty(fileP)) return; 104 | (DataContext as SettingViewModel)?.ChooseBackgroundImg(fileP); 105 | }, false); 106 | e.Handled = true; 107 | } 108 | 109 | /// 110 | /// 录制快捷键 111 | /// Record the shortcut key 112 | /// 113 | private void ShortcutKeyRecordAction(object sender, MouseButtonEventArgs e) 114 | { 115 | shortcutKeyText.Text = string.Empty; 116 | SharedInstance.Instance.isRecordingShortcutKey = true; 117 | } 118 | 119 | /// 120 | /// 监听快捷键录制 121 | /// Listen for the recording of the shortcut key 122 | /// 123 | /// 124 | protected override void OnKeyDown(KeyEventArgs e) 125 | { 126 | base.OnKeyDown(e); 127 | e.Handled = true; 128 | if (!SharedInstance.Instance.isRecordingShortcutKey) return; 129 | if (e.Key == Key.Enter) 130 | { 131 | SharedInstance.Instance.isRecordingShortcutKey = false; 132 | //UpdateShortStr(); 133 | } 134 | else 135 | { 136 | var key = e.Key == Key.System ? e.SystemKey : e.Key; 137 | // Ignore modifier keys. 138 | if (key is Key.LeftShift or Key.RightShift or Key.LeftCtrl or Key.RightCtrl or Key.LeftAlt or Key.RightAlt or Key.LWin or Key.RWin) return; 139 | StringBuilder shortcutText = new(); 140 | if ((Keyboard.Modifiers & ModifierKeys.Control) != 0) shortcutText.Append("Ctrl+"); 141 | if ((Keyboard.Modifiers & ModifierKeys.Shift) != 0) shortcutText.Append("Shift+"); 142 | if ((Keyboard.Modifiers & ModifierKeys.Alt) != 0) shortcutText.Append("Alt+"); 143 | 144 | shortcutText.Append(key.ToString()); 145 | shortcutKeyText.Text = shortcutText.ToString(); 146 | SharedInstance.Instance.registerHotKeyAction?.Invoke(Keyboard.Modifiers, key); 147 | UserConfig.Default.config.modifierKeys = Keyboard.Modifiers; 148 | UserConfig.Default.config.key = key; 149 | UserConfig.SaveConfig(); 150 | SharedInstance.Instance.isRecordingShortcutKey = false; 151 | } 152 | } 153 | 154 | /// 155 | /// 检查更新 156 | /// Check for updates 157 | /// 158 | /// 159 | /// 160 | private void CheckUpdateBtnAction(object sender, MouseButtonEventArgs e) 161 | { 162 | (DataContext as SettingViewModel)?.Update(); 163 | } 164 | 165 | /// 166 | /// 切换更新渠道 167 | /// 168 | /// 169 | /// 170 | private void ChooseUpdatePlaceAction(object sender, MouseButtonEventArgs e) 171 | { 172 | if (e.ClickCount != 1) 173 | return; 174 | e.Handled = true; 175 | updatePlacePopup.IsOpen = true; 176 | } 177 | 178 | /// 179 | /// 切换更新渠道 180 | /// 181 | /// 182 | /// 183 | private void SelectUpdatePlaceAction(object sender, MouseButtonEventArgs e) 184 | { 185 | if (e.ClickCount != 1) 186 | return; 187 | e.Handled = true; 188 | if (sender is not UIButton btn) 189 | return; 190 | UserConfig.Default.config.updatePlace = btn.title switch 191 | { 192 | "GitHub" => 0, 193 | "Gitee" => 1, 194 | _ => UserConfig.Default.config.updatePlace 195 | }; 196 | updatePlaceText.Text = btn.title; 197 | UserConfig.SaveConfig(); 198 | updatePlacePopup.IsOpen = false; 199 | (DataContext as SettingViewModel)?.CheckUpdate(); 200 | } 201 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/ViewModel/MainViewModel.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:MainViewModel.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/9/22 16:17:56 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System.Windows; 10 | using CommunityToolkit.Mvvm.ComponentModel; 11 | using MMClipboard.View; 12 | 13 | 14 | namespace MMClipboard.ViewModel; 15 | 16 | public class MainViewModel : ObservableObject 17 | { 18 | private object _currentView; 19 | 20 | public object currentView 21 | { 22 | get => _currentView; 23 | private set 24 | { 25 | _currentView = value; 26 | OnPropertyChanged(); 27 | } 28 | } 29 | 30 | public MainViewModel(Window wd) 31 | { 32 | currentView = new ClipboardHistory(wd); 33 | } 34 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/ViewModel/SettingViewModel.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:SettingViewModel.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/12/18 12:17:56 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Text; 11 | using System.Windows; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using CommunityToolkit.Mvvm.ComponentModel; 15 | using HtKit; 16 | using MMClipboard.Tool.AppUpdate; 17 | using MMClipboard.UserConfigs; 18 | using MMClipboard.View; 19 | 20 | 21 | namespace MMClipboard.ViewModel; 22 | 23 | public class SettingViewModel : ObservableObject 24 | { 25 | // 是否开机启动 26 | public bool isAutoStart 27 | { 28 | get => _isAutoStart; 29 | set 30 | { 31 | UserConfig.Default.config.isAutoStart = value; 32 | AutoStart.SetAutoStart("妙剪记", "妙剪记", value); 33 | UserConfig.SaveConfig(); 34 | SetProperty(ref _isAutoStart, value); 35 | } 36 | } 37 | private bool _isAutoStart = UserConfig.Default.config.isAutoStart; 38 | 39 | // 启动后最小化 40 | public bool isStartMinimize 41 | { 42 | get => _isStartMinimize; 43 | set 44 | { 45 | UserConfig.Default.config.isStartMinimize = value; 46 | UserConfig.SaveConfig(); 47 | SetProperty(ref _isStartMinimize, value); 48 | } 49 | } 50 | private bool _isStartMinimize = UserConfig.Default.config.isStartMinimize; 51 | 52 | // 是否复制文件 53 | // public bool isCopyFile 54 | // { 55 | // get => _isCopyFile; 56 | // set 57 | // { 58 | // UserConfig.Default.config.isCopyFile = value; 59 | // UserConfig.SaveConfig(); 60 | // SetProperty(ref _isCopyFile, value); 61 | // } 62 | // } 63 | // private bool _isCopyFile = UserConfig.Default.config.isCopyFile; 64 | 65 | // 是否为小窗口 66 | public bool isSmall 67 | { 68 | get => _isSmall; 69 | set 70 | { 71 | UserConfig.Default.config.isSmall = value; 72 | UserConfig.SaveConfig(); 73 | SharedInstance.ChangeWindow(value); 74 | SetProperty(ref _isSmall, value); 75 | } 76 | } 77 | private bool _isSmall = UserConfig.Default.config.isSmall; 78 | 79 | // 复制完成后关闭 80 | public bool isCopiedClose 81 | { 82 | get => _isCopiedClose; 83 | set 84 | { 85 | UserConfig.Default.config.isCopiedClose = value; 86 | UserConfig.SaveConfig(); 87 | SetProperty(ref _isCopiedClose, value); 88 | } 89 | } 90 | private bool _isCopiedClose = UserConfig.Default.config.isCopiedClose; 91 | 92 | // 是否使用背景图片 93 | public bool isUseBackgroundImg 94 | { 95 | get => _isUseBackgroundImg; 96 | set 97 | { 98 | UserConfig.Default.config.isUseBackgroundImg = value; 99 | SharedInstance.Instance.backgroundChangeDelegate?.Invoke(value); 100 | backgroundImgVisibility = value ? Visibility.Visible : Visibility.Collapsed; 101 | UserConfig.SaveConfig(); 102 | SetProperty(ref _isUseBackgroundImg, value); 103 | } 104 | } 105 | private bool _isUseBackgroundImg = UserConfig.Default.config.isUseBackgroundImg; 106 | 107 | public BitmapImage backgroundImg 108 | { 109 | get => _backgroundImg; 110 | set => SetProperty(ref _backgroundImg, value); 111 | } 112 | private BitmapImage _backgroundImg = UserConfig.Default.config.bgImgSource; 113 | 114 | public Visibility backgroundImgVisibility 115 | { 116 | get => _backgroundImgVisibility; 117 | set => SetProperty(ref _backgroundImgVisibility, value); 118 | } 119 | private Visibility _backgroundImgVisibility = UserConfig.Default.config.isUseBackgroundImg ? Visibility.Visible : Visibility.Collapsed; 120 | 121 | public Color selectColor 122 | { 123 | get => _selectColor; 124 | set 125 | { 126 | solidColorBrush = new SolidColorBrush(value); 127 | SharedInstance.Instance.backgroundColorChangeDelegate?.Invoke(solidColorBrush); 128 | UserConfig.Default.config.pageBackgroundColor = value.ToString(); 129 | UserConfig.SaveConfig(); 130 | SetProperty(ref _selectColor, value); 131 | } 132 | } 133 | private Color _selectColor = HtColor.ColorWithHex(UserConfig.Default.config.pageBackgroundColor); 134 | 135 | public SolidColorBrush solidColorBrush 136 | { 137 | get => _solidColorBrush; 138 | private set => SetProperty(ref _solidColorBrush, value); 139 | } 140 | private SolidColorBrush _solidColorBrush = HtColor.GetBrushWithString(UserConfig.Default.config.pageBackgroundColor); 141 | 142 | /// 143 | /// 本地版本号 144 | /// 145 | public string localVersion 146 | { 147 | get => _localVersion; 148 | private set => SetProperty(ref _localVersion, value); 149 | } 150 | private string _localVersion; 151 | 152 | /// 153 | /// 今年 154 | /// 155 | public static int thisYear => DateTime.Today.Year; 156 | 157 | /// 158 | /// 更新按钮标题 159 | /// 160 | public string updateBtnTitle 161 | { 162 | get => _updateBtnTitle; 163 | private set => SetProperty(ref _updateBtnTitle, value); 164 | } 165 | private string _updateBtnTitle = "检查更新"; 166 | 167 | public string hotkeyString 168 | { 169 | get => _hotkeyString; 170 | private set => SetProperty(ref _hotkeyString, value); 171 | } 172 | private string _hotkeyString; 173 | 174 | private VersionModel m_versionDataModel; 175 | 176 | private bool m_isNeedUpdate; 177 | 178 | /// 179 | /// 构造函数 180 | /// initialization 181 | /// 182 | public SettingViewModel() 183 | { 184 | localVersion = AppUpdateManager.ReadLocalVersionNo(); 185 | StringBuilder shortcutText = new(); 186 | var m = UserConfig.Default.config.modifierKeys.ToString().Replace(',', '+'); 187 | shortcutText.Append($"{m}+"); 188 | shortcutText.Append(UserConfig.Default.config.key.ToString()); 189 | hotkeyString = shortcutText.ToString(); 190 | CheckUpdate(); 191 | } 192 | 193 | /// 194 | /// 选择背景图片 195 | /// Choose the background image 196 | /// 197 | /// 198 | public void ChooseBackgroundImg(string fileP) 199 | { 200 | try 201 | { 202 | var bmp = new BitmapImage(new Uri(fileP)); 203 | backgroundImg = bmp; 204 | SharedInstance.Instance.backgroundImageChangeDelegate?.Invoke(backgroundImg); 205 | UserConfig.Default.config.pageBackgroundImg = fileP; 206 | UserConfig.SaveConfig(); 207 | } 208 | catch (Exception e) 209 | { 210 | e.Message.Debug(); 211 | } 212 | } 213 | 214 | /// 215 | /// App更新 216 | /// App updates 217 | /// 218 | public void Update() 219 | { 220 | if (m_isNeedUpdate) 221 | OpenUpdateWindow(); 222 | else 223 | CheckUpdate(); 224 | } 225 | 226 | /// 227 | /// App检查更新 228 | /// The App checks for updates 229 | /// 230 | public void CheckUpdate() 231 | { 232 | AppUpdateManager.Check((update, mod) => 233 | { 234 | m_versionDataModel = mod; 235 | m_isNeedUpdate = update; 236 | updateBtnTitle = update ? $"有新版本:{mod.version}" : $"不需要更新:{mod.version}"; 237 | }); 238 | } 239 | 240 | /// 241 | /// 打开更新窗口 242 | /// Open the update window 243 | /// 244 | private void OpenUpdateWindow() 245 | { 246 | AppUpdateWindow updateWindow = new(m_versionDataModel) 247 | { 248 | ShowActivated = true 249 | }; 250 | updateWindow.ShowDialog(); 251 | } 252 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/ViewModel/ShortcutPhraseViewModel.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:ShortcutPhraseViewModel.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2024-02-03 11:24:29 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Collections.Generic; 11 | using CommunityToolkit.Mvvm.ComponentModel; 12 | using MMClipboard.Model; 13 | using MMClipboard.Tool; 14 | using MMClipboard.UserConfigs; 15 | using MMClipboard.View; 16 | 17 | 18 | namespace MMClipboard.ViewModel; 19 | 20 | public class ShortcutPhraseViewModel : ObservableObject, IDisposable 21 | { 22 | public List phrases 23 | { 24 | get => _clips; 25 | private set => SetProperty(ref _clips, value); 26 | } 27 | private List _clips; 28 | 29 | public WindowBackgroundModel backgroundModel { get; } = new(); 30 | 31 | private ShortcutPhraseWindow m_window; 32 | 33 | /// 34 | /// init 35 | /// 36 | public ShortcutPhraseViewModel(ShortcutPhraseWindow window) 37 | { 38 | m_window = window; 39 | RefreshData(); 40 | } 41 | 42 | /// 43 | /// 复制粘贴短语 44 | /// 45 | /// 46 | public void CopyText(string phrase) 47 | { 48 | if (string.IsNullOrEmpty(phrase)) 49 | return; 50 | CopyAndPasteHelper.CopyAndPasteText(phrase, () => 51 | { 52 | if (UserConfig.Default.config.isCopiedClose) 53 | m_window.Close(); 54 | }); 55 | } 56 | 57 | /// 58 | /// 添加短语 59 | /// 60 | public void AddPhrase(ShortcutPhraseModel phraseModel) 61 | { 62 | if (DataBaseController.AddPhrase(phraseModel)) 63 | RefreshData(); 64 | } 65 | 66 | /// 67 | /// 删除短语 68 | /// 69 | /// 70 | public void DeletePhrase(ShortcutPhraseModel model) 71 | { 72 | DataBaseController.DeletePhrase(model); 73 | RefreshData(); 74 | } 75 | 76 | /// 77 | /// 获取所有短语 78 | /// 79 | public void RefreshData() 80 | { 81 | phrases = DataBaseController.GetAllPhrases(); 82 | } 83 | 84 | public void Dispose() 85 | { 86 | backgroundModel.Dispose(); 87 | } 88 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/ViewModel/TaskbarViewModel.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:TaskbarViewModel.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2023/9/22 14:16:36 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | using System.Windows; 9 | using System.Windows.Input; 10 | using CommunityToolkit.Mvvm.ComponentModel; 11 | using CommunityToolkit.Mvvm.Input; 12 | 13 | namespace MMClipboard.ViewModel 14 | { 15 | public class TaskbarViewModel : ObservableObject 16 | { 17 | public double FixWidth { get; set; } 18 | 19 | public ICommand taskbarMenuCommand { get; private set; } = new RelayCommand(TaskbarMenuAction); 20 | public RelayCommand clickTaskbarCommand { get; private set; } = new(ClickTaskbar); 21 | 22 | private static void TaskbarMenuAction(string par) 23 | { 24 | if (par is null) 25 | return; 26 | switch (par) 27 | { 28 | case "Setting": 29 | SharedInstance.ShowSettingWindow(); 30 | break; 31 | case "Quit": 32 | Application.Current.Shutdown(); 33 | break; 34 | } 35 | } 36 | 37 | private static void ClickTaskbar() 38 | { 39 | SharedInstance.ShowSettingWindow(); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /MMClipboard.Desktop/ViewModel/WindowBackgroundModel.cs: -------------------------------------------------------------------------------- 1 | /*🏷️---------------------------------------------------------------- 2 | *📄 文件名:WindowBackgroundModel.cs 3 | *🏷️ 4 | *👨🏽‍💻 创建者:Ht 5 | *⏱️ 创建时间:2024-02-03 11:45:20 6 | *🏷️----------------------------------------------------------------*/ 7 | 8 | 9 | using System; 10 | using System.Windows; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using CommunityToolkit.Mvvm.ComponentModel; 14 | using HtKit; 15 | using MMClipboard.UserConfigs; 16 | 17 | 18 | namespace MMClipboard.ViewModel; 19 | 20 | public class WindowBackgroundModel : ObservableObject, IDisposable 21 | { 22 | public BitmapSource backgroundImage 23 | { 24 | get => _backgroundImage; 25 | private set => SetProperty(ref _backgroundImage, value); 26 | } 27 | private BitmapSource _backgroundImage = UserConfig.Default.config.bgImgSource; 28 | 29 | public Visibility backgroundImageVisibility 30 | { 31 | get => _backgroundImageVisibility; 32 | private set => SetProperty(ref _backgroundImageVisibility, value); 33 | } 34 | private Visibility _backgroundImageVisibility = UserConfig.Default.config.isUseBackgroundImg ? Visibility.Visible : Visibility.Collapsed; 35 | 36 | public SolidColorBrush backgroundColor 37 | { 38 | get => _solidColorBrush; 39 | private set => SetProperty(ref _solidColorBrush, value); 40 | } 41 | private SolidColorBrush _solidColorBrush = HtColor.GetBrushWithString(UserConfig.Default.config.pageBackgroundColor); 42 | 43 | public WindowBackgroundModel() 44 | { 45 | SharedInstance.Instance.backgroundColorChangeDelegate += BackgroundColorChange; 46 | SharedInstance.Instance.backgroundChangeDelegate += BackgroundChange; 47 | SharedInstance.Instance.backgroundImageChangeDelegate += BackgroundImageChange; 48 | } 49 | 50 | private void BackgroundChange(bool use) 51 | { 52 | backgroundImageVisibility = use ? Visibility.Visible : Visibility.Collapsed; 53 | } 54 | 55 | private void BackgroundColorChange(SolidColorBrush color) 56 | { 57 | backgroundColor = color; 58 | } 59 | 60 | private void BackgroundImageChange(BitmapSource img) 61 | { 62 | backgroundImage = img; 63 | } 64 | 65 | public void Dispose() 66 | { 67 | SharedInstance.Instance.backgroundColorChangeDelegate -= BackgroundColorChange; 68 | SharedInstance.Instance.backgroundChangeDelegate -= BackgroundChange; 69 | SharedInstance.Instance.backgroundImageChangeDelegate -= BackgroundImageChange; 70 | GC.Collect(); 71 | } 72 | } -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/.idea/MMClipboard.UpdateTool_Python.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 13 | 14 | 19 | 20 | 21 | 23 | { 24 | "customColor": "", 25 | "associatedIndex": 1 26 | } 27 | 28 | 29 | 30 | 31 | 32 | 35 | { 36 | "keyToString": { 37 | "RunOnceActivity.OpenProjectViewOnStart": "true", 38 | "RunOnceActivity.ShowReadmeOnStart": "true", 39 | "git-widget-placeholder": "main", 40 | "ignore.virus.scanning.warn.message": "true", 41 | "node.js.detected.package.eslint": "true", 42 | "node.js.detected.package.tslint": "true", 43 | "node.js.selected.package.eslint": "(autodetect)", 44 | "node.js.selected.package.tslint": "(autodetect)", 45 | "nodejs_package_manager_path": "npm", 46 | "settings.editor.selected.configurable": "preferences.pluginManager", 47 | "vue.rearranger.settings.migration": "true" 48 | } 49 | } 50 | 51 | 52 | 53 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 1703235474779 62 | 75 | 76 | 77 | 78 | 80 | -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/UpdateTool.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import subprocess 4 | import sys 5 | import time 6 | 7 | 8 | def runMainApp(): 9 | exePath = os.path.abspath('.') + "\\MMClipboard.exe" 10 | if not (os.path.exists(exePath)): 11 | return 12 | subprocess.Popen(exePath) 13 | 14 | 15 | def moveFile(old_path, new_path): 16 | if not os.path.exists(oldP): 17 | return 18 | filelist = os.listdir(old_path) 19 | for file in filelist: 20 | # 源文件 21 | src = os.path.join(old_path, file) 22 | # 目标文件 23 | dst = os.path.join(new_path, file) 24 | if os.path.isdir(src): 25 | 26 | if not os.path.exists(dst): 27 | os.makedirs(dst, True) 28 | cfiles = os.listdir(src) 29 | for c in cfiles: 30 | # 源文件 31 | sourceFileP = os.path.join(old_path, file + '\\' + c) 32 | # 目标文件 33 | targetFileP = os.path.join(new_path, file + '\\' + c) 34 | if os.path.exists(targetFileP): 35 | os.remove(targetFileP) 36 | shutil.move(sourceFileP, targetFileP) 37 | else: 38 | if os.path.exists(dst): 39 | os.remove(dst) 40 | shutil.move(src, dst) 41 | 42 | 43 | # 按间距中的绿色按钮以运行脚本。 44 | if __name__ == '__main__': 45 | if len(sys.argv) > 1: 46 | if sys.argv[1] == 'com.ht.mmclipboard': 47 | time.sleep(1) 48 | oldP = os.path.abspath('.') + '\\Temp\\' 49 | newP = os.path.abspath('.') 50 | moveFile(oldP, newP) 51 | runMainApp() 52 | shutil.rmtree(oldP) 53 | -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/UpdateTool.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python ; coding: utf-8 -*- 2 | 3 | 4 | a = Analysis( 5 | ['UpdateTool.py'], 6 | pathex=[], 7 | binaries=[], 8 | datas=[], 9 | hiddenimports=[], 10 | hookspath=[], 11 | hooksconfig={}, 12 | runtime_hooks=[], 13 | excludes=[], 14 | noarchive=False, 15 | ) 16 | pyz = PYZ(a.pure) 17 | 18 | exe = EXE( 19 | pyz, 20 | a.scripts, 21 | a.binaries, 22 | a.datas, 23 | [], 24 | name='UpdateTool', 25 | debug=False, 26 | bootloader_ignore_signals=False, 27 | strip=False, 28 | upx=True, 29 | upx_exclude=[], 30 | runtime_tmpdir=None, 31 | console=False, 32 | disable_windowed_traceback=False, 33 | argv_emulation=False, 34 | target_arch=None, 35 | codesign_identity=None, 36 | entitlements_file=None, 37 | icon=['ddd.ico'], 38 | ) 39 | -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/build/UpdateTool/PYZ-00.pyz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.UpdateTool_Python/build/UpdateTool/PYZ-00.pyz -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/build/UpdateTool/PYZ-00.toc: -------------------------------------------------------------------------------- 1 | ('F:\\WPFProjects\\MMClipboard\\MMClipboard.UpdateTool_Python\\build\\UpdateTool\\PYZ-00.pyz', 2 | [('_compat_pickle', 3 | 'D:\\Python\\Python39\\lib\\_compat_pickle.py', 4 | 'PYMODULE'), 5 | ('_compression', 'D:\\Python\\Python39\\lib\\_compression.py', 'PYMODULE'), 6 | ('_py_abc', 'D:\\Python\\Python39\\lib\\_py_abc.py', 'PYMODULE'), 7 | ('_pydecimal', 'D:\\Python\\Python39\\lib\\_pydecimal.py', 'PYMODULE'), 8 | ('_strptime', 'D:\\Python\\Python39\\lib\\_strptime.py', 'PYMODULE'), 9 | ('_threading_local', 10 | 'D:\\Python\\Python39\\lib\\_threading_local.py', 11 | 'PYMODULE'), 12 | ('argparse', 'D:\\Python\\Python39\\lib\\argparse.py', 'PYMODULE'), 13 | ('base64', 'D:\\Python\\Python39\\lib\\base64.py', 'PYMODULE'), 14 | ('bisect', 'D:\\Python\\Python39\\lib\\bisect.py', 'PYMODULE'), 15 | ('bz2', 'D:\\Python\\Python39\\lib\\bz2.py', 'PYMODULE'), 16 | ('calendar', 'D:\\Python\\Python39\\lib\\calendar.py', 'PYMODULE'), 17 | ('configparser', 'D:\\Python\\Python39\\lib\\configparser.py', 'PYMODULE'), 18 | ('contextlib', 'D:\\Python\\Python39\\lib\\contextlib.py', 'PYMODULE'), 19 | ('contextvars', 'D:\\Python\\Python39\\lib\\contextvars.py', 'PYMODULE'), 20 | ('copy', 'D:\\Python\\Python39\\lib\\copy.py', 'PYMODULE'), 21 | ('csv', 'D:\\Python\\Python39\\lib\\csv.py', 'PYMODULE'), 22 | ('datetime', 'D:\\Python\\Python39\\lib\\datetime.py', 'PYMODULE'), 23 | ('decimal', 'D:\\Python\\Python39\\lib\\decimal.py', 'PYMODULE'), 24 | ('email', 'D:\\Python\\Python39\\lib\\email\\__init__.py', 'PYMODULE'), 25 | ('email._encoded_words', 26 | 'D:\\Python\\Python39\\lib\\email\\_encoded_words.py', 27 | 'PYMODULE'), 28 | ('email._header_value_parser', 29 | 'D:\\Python\\Python39\\lib\\email\\_header_value_parser.py', 30 | 'PYMODULE'), 31 | ('email._parseaddr', 32 | 'D:\\Python\\Python39\\lib\\email\\_parseaddr.py', 33 | 'PYMODULE'), 34 | ('email._policybase', 35 | 'D:\\Python\\Python39\\lib\\email\\_policybase.py', 36 | 'PYMODULE'), 37 | ('email.base64mime', 38 | 'D:\\Python\\Python39\\lib\\email\\base64mime.py', 39 | 'PYMODULE'), 40 | ('email.charset', 'D:\\Python\\Python39\\lib\\email\\charset.py', 'PYMODULE'), 41 | ('email.contentmanager', 42 | 'D:\\Python\\Python39\\lib\\email\\contentmanager.py', 43 | 'PYMODULE'), 44 | ('email.encoders', 45 | 'D:\\Python\\Python39\\lib\\email\\encoders.py', 46 | 'PYMODULE'), 47 | ('email.errors', 'D:\\Python\\Python39\\lib\\email\\errors.py', 'PYMODULE'), 48 | ('email.feedparser', 49 | 'D:\\Python\\Python39\\lib\\email\\feedparser.py', 50 | 'PYMODULE'), 51 | ('email.generator', 52 | 'D:\\Python\\Python39\\lib\\email\\generator.py', 53 | 'PYMODULE'), 54 | ('email.header', 'D:\\Python\\Python39\\lib\\email\\header.py', 'PYMODULE'), 55 | ('email.headerregistry', 56 | 'D:\\Python\\Python39\\lib\\email\\headerregistry.py', 57 | 'PYMODULE'), 58 | ('email.iterators', 59 | 'D:\\Python\\Python39\\lib\\email\\iterators.py', 60 | 'PYMODULE'), 61 | ('email.message', 'D:\\Python\\Python39\\lib\\email\\message.py', 'PYMODULE'), 62 | ('email.parser', 'D:\\Python\\Python39\\lib\\email\\parser.py', 'PYMODULE'), 63 | ('email.policy', 'D:\\Python\\Python39\\lib\\email\\policy.py', 'PYMODULE'), 64 | ('email.quoprimime', 65 | 'D:\\Python\\Python39\\lib\\email\\quoprimime.py', 66 | 'PYMODULE'), 67 | ('email.utils', 'D:\\Python\\Python39\\lib\\email\\utils.py', 'PYMODULE'), 68 | ('fnmatch', 'D:\\Python\\Python39\\lib\\fnmatch.py', 'PYMODULE'), 69 | ('fractions', 'D:\\Python\\Python39\\lib\\fractions.py', 'PYMODULE'), 70 | ('getopt', 'D:\\Python\\Python39\\lib\\getopt.py', 'PYMODULE'), 71 | ('gettext', 'D:\\Python\\Python39\\lib\\gettext.py', 'PYMODULE'), 72 | ('gzip', 'D:\\Python\\Python39\\lib\\gzip.py', 'PYMODULE'), 73 | ('hashlib', 'D:\\Python\\Python39\\lib\\hashlib.py', 'PYMODULE'), 74 | ('importlib', 75 | 'D:\\Python\\Python39\\lib\\importlib\\__init__.py', 76 | 'PYMODULE'), 77 | ('importlib._bootstrap', 78 | 'D:\\Python\\Python39\\lib\\importlib\\_bootstrap.py', 79 | 'PYMODULE'), 80 | ('importlib._bootstrap_external', 81 | 'D:\\Python\\Python39\\lib\\importlib\\_bootstrap_external.py', 82 | 'PYMODULE'), 83 | ('importlib.abc', 'D:\\Python\\Python39\\lib\\importlib\\abc.py', 'PYMODULE'), 84 | ('importlib.machinery', 85 | 'D:\\Python\\Python39\\lib\\importlib\\machinery.py', 86 | 'PYMODULE'), 87 | ('importlib.metadata', 88 | 'D:\\Python\\Python39\\lib\\importlib\\metadata.py', 89 | 'PYMODULE'), 90 | ('importlib.util', 91 | 'D:\\Python\\Python39\\lib\\importlib\\util.py', 92 | 'PYMODULE'), 93 | ('logging', 'D:\\Python\\Python39\\lib\\logging\\__init__.py', 'PYMODULE'), 94 | ('lzma', 'D:\\Python\\Python39\\lib\\lzma.py', 'PYMODULE'), 95 | ('numbers', 'D:\\Python\\Python39\\lib\\numbers.py', 'PYMODULE'), 96 | ('optparse', 'D:\\Python\\Python39\\lib\\optparse.py', 'PYMODULE'), 97 | ('pathlib', 'D:\\Python\\Python39\\lib\\pathlib.py', 'PYMODULE'), 98 | ('pickle', 'D:\\Python\\Python39\\lib\\pickle.py', 'PYMODULE'), 99 | ('pprint', 'D:\\Python\\Python39\\lib\\pprint.py', 'PYMODULE'), 100 | ('py_compile', 'D:\\Python\\Python39\\lib\\py_compile.py', 'PYMODULE'), 101 | ('quopri', 'D:\\Python\\Python39\\lib\\quopri.py', 'PYMODULE'), 102 | ('random', 'D:\\Python\\Python39\\lib\\random.py', 'PYMODULE'), 103 | ('selectors', 'D:\\Python\\Python39\\lib\\selectors.py', 'PYMODULE'), 104 | ('shutil', 'D:\\Python\\Python39\\lib\\shutil.py', 'PYMODULE'), 105 | ('signal', 'D:\\Python\\Python39\\lib\\signal.py', 'PYMODULE'), 106 | ('socket', 'D:\\Python\\Python39\\lib\\socket.py', 'PYMODULE'), 107 | ('statistics', 'D:\\Python\\Python39\\lib\\statistics.py', 'PYMODULE'), 108 | ('string', 'D:\\Python\\Python39\\lib\\string.py', 'PYMODULE'), 109 | ('stringprep', 'D:\\Python\\Python39\\lib\\stringprep.py', 'PYMODULE'), 110 | ('subprocess', 'D:\\Python\\Python39\\lib\\subprocess.py', 'PYMODULE'), 111 | ('tarfile', 'D:\\Python\\Python39\\lib\\tarfile.py', 'PYMODULE'), 112 | ('textwrap', 'D:\\Python\\Python39\\lib\\textwrap.py', 'PYMODULE'), 113 | ('threading', 'D:\\Python\\Python39\\lib\\threading.py', 'PYMODULE'), 114 | ('token', 'D:\\Python\\Python39\\lib\\token.py', 'PYMODULE'), 115 | ('tokenize', 'D:\\Python\\Python39\\lib\\tokenize.py', 'PYMODULE'), 116 | ('tracemalloc', 'D:\\Python\\Python39\\lib\\tracemalloc.py', 'PYMODULE'), 117 | ('typing', 'D:\\Python\\Python39\\lib\\typing.py', 'PYMODULE'), 118 | ('urllib', 'D:\\Python\\Python39\\lib\\urllib\\__init__.py', 'PYMODULE'), 119 | ('urllib.parse', 'D:\\Python\\Python39\\lib\\urllib\\parse.py', 'PYMODULE'), 120 | ('uu', 'D:\\Python\\Python39\\lib\\uu.py', 'PYMODULE'), 121 | ('zipfile', 'D:\\Python\\Python39\\lib\\zipfile.py', 'PYMODULE')]) 122 | -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/build/UpdateTool/UpdateTool.pkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.UpdateTool_Python/build/UpdateTool/UpdateTool.pkg -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/build/UpdateTool/base_library.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.UpdateTool_Python/build/UpdateTool/base_library.zip -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/build/UpdateTool/localpycs/pyimod01_archive.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.UpdateTool_Python/build/UpdateTool/localpycs/pyimod01_archive.pyc -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/build/UpdateTool/localpycs/pyimod02_importers.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.UpdateTool_Python/build/UpdateTool/localpycs/pyimod02_importers.pyc -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/build/UpdateTool/localpycs/pyimod03_ctypes.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.UpdateTool_Python/build/UpdateTool/localpycs/pyimod03_ctypes.pyc -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/build/UpdateTool/localpycs/pyimod04_pywin32.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.UpdateTool_Python/build/UpdateTool/localpycs/pyimod04_pywin32.pyc -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/build/UpdateTool/localpycs/struct.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.UpdateTool_Python/build/UpdateTool/localpycs/struct.pyc -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/build/UpdateTool/warn-UpdateTool.txt: -------------------------------------------------------------------------------- 1 | 2 | This file lists modules PyInstaller was not able to find. This does not 3 | necessarily mean this module is required for running your program. Python and 4 | Python 3rd-party packages include a lot of conditional or optional modules. For 5 | example the module 'ntpath' only exists on Windows, whereas the module 6 | 'posixpath' only exists on Posix systems. 7 | 8 | Types if import: 9 | * top-level: imported at the top-level - look at these first 10 | * conditional: imported within an if-statement 11 | * delayed: imported within a function 12 | * optional: imported within a try-except-statement 13 | 14 | IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for 15 | tracking down the missing module yourself. Thanks! 16 | 17 | missing module named 'org.python' - imported by copy (optional) 18 | missing module named pwd - imported by posixpath (delayed, conditional), shutil (optional), tarfile (optional), pathlib (delayed, conditional, optional), subprocess (optional) 19 | missing module named org - imported by pickle (optional) 20 | missing module named _posixsubprocess - imported by subprocess (optional) 21 | missing module named grp - imported by shutil (optional), tarfile (optional), pathlib (delayed, optional), subprocess (optional) 22 | missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional) 23 | excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional) 24 | missing module named pep517 - imported by importlib.metadata (delayed) 25 | missing module named posix - imported by os (conditional, optional), shutil (conditional), importlib._bootstrap_external (conditional) 26 | missing module named resource - imported by posix (top-level) 27 | -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/ddd.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.UpdateTool_Python/ddd.ico -------------------------------------------------------------------------------- /MMClipboard.UpdateTool_Python/dist/UpdateTool.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/MMClipboard.UpdateTool_Python/dist/UpdateTool.exe -------------------------------------------------------------------------------- /MMClipboard.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34330.188 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtKit", "HtKit\HtKit.csproj", "{BFBA42E3-717E-4504-983A-C008EDA85883}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MMClipboard", "MMClipboard.Desktop\MMClipboard.csproj", "{D69C7B7A-D72A-4AD1-840E-E5976FB92D31}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {BFBA42E3-717E-4504-983A-C008EDA85883}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {BFBA42E3-717E-4504-983A-C008EDA85883}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {BFBA42E3-717E-4504-983A-C008EDA85883}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {BFBA42E3-717E-4504-983A-C008EDA85883}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {D69C7B7A-D72A-4AD1-840E-E5976FB92D31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {D69C7B7A-D72A-4AD1-840E-E5976FB92D31}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {D69C7B7A-D72A-4AD1-840E-E5976FB92D31}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {D69C7B7A-D72A-4AD1-840E-E5976FB92D31}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {C41AEFF3-5EA0-4D3D-AE07-8B02BE72382D} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |

妙剪记

4 | 5 | 这是一款漂亮的(自认为的🤣)Windows桌面端剪切板历史记录软件,目前支持**文本**、**图片**、**文件**的复制/剪切记录,所有数据均保存到本地数据库中,你的数据你自己掌控,**我不会上传你的任何数据至云端**。 6 | 7 | 如果你喜欢这个项目或者它对你有用,请给我点个Star,感谢! 8 | 9 | ### 🍋功能介绍 10 | - 🍑记录你的剪贴板历史✅ 11 | - 记录中将显示该条数据是从什么软件复制来的✅ 12 | - 🍓横向排列和竖向排列两种方式✅ 13 | - 🍒记录内容数据类型✅ 14 | - 文本✅ 15 | - 如果复制的文本是网页地址,可直接右键打开该页面,程序自动识别内容✅ 16 | - 如果是本地文件(夹)地址,可右键打开该目录✅ 17 | - 支持Emoji内容显示✅ 18 | - 暂不支持微信自己的表情包,复制出来是空的~❌ 19 | - 图片✅ 20 | - 截图软件生成的图片会保存一份到程序Cache目录中,删除数据条目时一并删除✅ 21 | - 文件✅ 22 | - 🍆数据筛选✅ 23 | - 按日期✅ 24 | - 按类型✅ 25 | - 是否收藏✅ 26 | - 🥑收藏记录✅ 27 | - 🥕搜索✅ 28 | - 文本内容✅ 29 | - 文件名✅ 30 | - 🍄一键清空所选日期的所有数据✅ 31 | - 🌰开机启动(默认开启)✅ 32 | - 🥒自定义窗口背景图(色)✅ 33 | - 🌽自定义快捷键✅ 34 | - 🍄App在线更新✅ 35 | - 🍄快捷短语功能✅ 36 | 37 | ### 🦤计划加入功能 38 | - 快捷短语功能待完善。待完善部分功能:编辑、修改、取别名等。 39 | - 更丰富的右键菜单。 40 | 41 | ### 🎃下载 42 | - 无网络情况的用户请移步至 [Releases](https://github.com/ProjectLion/MMClipboard/releases) 下载安装包or压缩包后安装使用。 43 | - 存在网络情况的朋友请移步至 [Gitee](https://gitee.com/HtReturnTrue/MMClipboard) 或者直达 [Releases](https://gitee.com/HtReturnTrue/MMClipboard/releases) 下载安装包or压缩包后安装使用。 44 | 45 | ### 🖥️使用环境 46 | - Windows10.0.17763.0 later✅ 47 | - Windows11所有版本✅ 48 | 49 | ### 🔧使用 50 | - **剪切板历史记录功能**:安装后双击运行程序即开启监听,使用你定义的快捷键(默认Alt+C)呼出记录窗口点击相应的记录即可粘贴到你当前鼠标光标处。 51 | - **快捷短语功能**:使用快捷键(Alt+~)呼出短语列表,点击记录即可粘贴到你当前鼠标光标处。 52 | 53 | ### 🔧使用过程中出现问题的解决办法 54 | - **如果出现无法监听复制内容的情况,请右下角退出App后以管理员方式运行** 55 | - **如果出现无法粘贴内容,可能是粘贴目的地不支持该数据格式,如VS Code中不支持插入图片** 56 | - 如果你是一名开发者,有新的想法,欢迎 [fork](https://github.com/ProjectLion/MMClipboard/forks) 本项目并发起 [PR](https://github.com/ProjectLion/MMClipboard/pulls),我将把你的名字写入贡献者名单 57 | - 其他问题请提 [Issues](https://github.com/ProjectLion/MMClipboard/issues),我会尽快解决问题。 58 | 59 | ### 📸应用截图 60 | - 竖屏(小窗口) 61 | ![](./doc/preview/SmallSnip.png) 62 | - 横屏 63 | ![](./doc/preview/MaxSnip.png) 64 | - 快捷短语功能 65 | ![](./doc/preview/ShortcutSnip.png) 66 | 67 | ## 🙏致谢 68 | #### 感谢以下无私奉献的开源库的作者和贡献者们(排名不分先后) 69 | - C# Zip解压缩支持库 - [__SharpZipLib__](https://github.com/icsharpcode/SharpZipLib) 70 | - WPF Emoji表情包支持库 - [__Emoji.Wpf__](https://github.com/samhocevar/emoji.wpf) 71 | - C# Json解析支持库 - [__Newtonsoft.Json__](https://github.com/JamesNK/Newtonsoft.Json) 72 | - C# SQLite ORM支持库 - [__FreeSql__](https://github.com/dotnetcore/FreeSql) 73 | - WPF Theme、UI组件工具包 - [__MaterialDesignThemes__](https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit) 74 | - WPF MVVM工具包 - [__CommunityToolkit.Mvvm__](https://github.com/CommunityToolkit/dotnet) 75 | - WPF 系统托盘图标工具包 - [__Hardcodet.NotifyIcon.Wpf__](https://github.com/hardcodet/wpf-notifyicon) 76 | - WPF xaml行为事件工具包 - [__Microsoft.Xaml.Behaviors.Wpf__](https://github.com/Microsoft/XamlBehaviorsWpf) 77 | - WPF 内存释放工具包 - [__Lierda.WPFHelper__](https://www.nuget.org/packages/Lierda.WPFHelper) 78 | - WPF、WinForm全局监听按键工具包 - [__NHotkey__](https://github.com/thomaslevesque/NHotkey) 79 | 80 | ## ❗免责声明 81 | **禁止任何人以任何形式将其用于任何非法用途,对于使用该程序所造成的任何后果,所有创作者不承担任何责任。** 82 | **该软件不存在任何收费,谨防上当受骗。** 83 | **软件贩子勿扰,违规违法勿扰,二次开发请务必遵守开源协议。** 84 | 85 | ### 🤙联系我 86 | - 本项目只支持Github的 [__Issues__](https://github.com/ProjectLion/MMClipboard/issues) 交流,没有Q群。 87 | 88 | ### 🏅支持该项目 89 | 感谢你对本项目的支持,在你觉得本项目对你有帮助的前提下,愿意提供赞助我将非常感激。 90 | 91 | ### ✨赞助方式 92 | ![](./doc/QRCode/WeChat.jpg) 93 | 94 | # License 95 | 96 | MMClipboard is licensed under [MIT License](./LICENSE). 97 | 98 | Copyright © 2023-2024 by Ht. 99 | -------------------------------------------------------------------------------- /VersionInfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.24.227.1", 3 | "updateMsg": "\n一、优化功能。\n二、新增快捷短语功能。", 4 | "updateUrl_Github": "https://github.com/ProjectLion/MMClipboard/releases/download/1.24.227.1/MMClipboard.zip", 5 | "updateUrl_Gitee": "https://gitee.com/HtReturnTrue/MMClipboard/releases/download/1.24.227.1/MMClipboard.zip", 6 | "updateTime": "2024-02-27", 7 | "fileSize": 99799701 8 | } -------------------------------------------------------------------------------- /doc/QRCode/WeChat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/doc/QRCode/WeChat.jpg -------------------------------------------------------------------------------- /doc/preview/MaxSnip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/doc/preview/MaxSnip.png -------------------------------------------------------------------------------- /doc/preview/ShortcutSnip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/doc/preview/ShortcutSnip.png -------------------------------------------------------------------------------- /doc/preview/SmallSnip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProjectLion/MMClipboard/a2acbdd7ffa34befdceccf9454b81e986fdcb766/doc/preview/SmallSnip.png --------------------------------------------------------------------------------