├── .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