NotifyIconController.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. using Clash.SDK.Models.Enums;
  2. using ClashDotNetFramework.Properties;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.ComponentModel;
  6. using System.Diagnostics;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Runtime.InteropServices;
  10. using System.Text;
  11. using System.Threading.Tasks;
  12. using System.Windows;
  13. using System.Windows.Forms;
  14. using WindowsProxy;
  15. using Application = System.Windows.Application;
  16. using Clipboard = System.Windows.Clipboard;
  17. namespace ClashDotNetFramework.Controllers
  18. {
  19. public class NotifyIconController
  20. {
  21. public NotifyIcon Icon;
  22. public ContextMenu Strip;
  23. public MenuItem proxyModeMenu;
  24. #region Public Control Function
  25. public void Start()
  26. {
  27. // 初始化菜单
  28. Strip = new ContextMenu();
  29. Strip.MenuItems.Add("Dashboard"); // 0
  30. Strip.MenuItems.Add("-"); // 1
  31. proxyModeMenu = new MenuItem("Proxy Mode");
  32. proxyModeMenu.MenuItems.Add("Direct");
  33. proxyModeMenu.MenuItems.Add("Rule");
  34. proxyModeMenu.MenuItems.Add("Global");
  35. Strip.MenuItems.Add(proxyModeMenu); // 2
  36. Strip.MenuItems.Add("System Proxy"); // 3
  37. Strip.MenuItems.Add("Process Proxy"); // 4
  38. Strip.MenuItems.Add("-"); // 5
  39. MenuItem openTerminalMenu = new MenuItem("Open Terminal With Proxy Set Up");
  40. openTerminalMenu.MenuItems.Add("Cmd");
  41. openTerminalMenu.MenuItems.Add("PowerShell");
  42. openTerminalMenu.MenuItems.Add("Windows Terminal");
  43. openTerminalMenu.MenuItems.Add("Fluent Terminal");
  44. Strip.MenuItems.Add(openTerminalMenu); // 6
  45. MenuItem copyCommandMenu = new MenuItem("Copy Proxy Setting Commands");
  46. copyCommandMenu.MenuItems.Add("Cmd");
  47. copyCommandMenu.MenuItems.Add("PowerShell");
  48. Strip.MenuItems.Add(copyCommandMenu); // 7
  49. MenuItem setTelegramProxyMenu = new MenuItem("Set Telegram Proxy");
  50. setTelegramProxyMenu.MenuItems.Add("Set Socks5 Proxy To Telegram");
  51. Strip.MenuItems.Add(setTelegramProxyMenu); // 8
  52. Strip.MenuItems.Add("-"); // 9
  53. MenuItem netFilterMenu = new MenuItem("NetFilter Driver");
  54. netFilterMenu.MenuItems.Add("Install NetFilter Driver");
  55. netFilterMenu.MenuItems.Add("Uninstall NetFilter Driver");
  56. Strip.MenuItems.Add(netFilterMenu); // 10
  57. Strip.MenuItems.Add("Enable UWP Loopback"); // 11
  58. Strip.MenuItems.Add("-"); // 12
  59. Strip.MenuItems.Add("Quit"); // 13
  60. // 设置属性并分配事件
  61. Strip.MenuItems[0].Click += OnDashboard_Click;
  62. proxyModeMenu.MenuItems[0].RadioCheck = true;
  63. proxyModeMenu.MenuItems[1].RadioCheck = true;
  64. proxyModeMenu.MenuItems[2].RadioCheck = true;
  65. proxyModeMenu.MenuItems[0].Click += OnProxyMode_Click;
  66. proxyModeMenu.MenuItems[1].Click += OnProxyMode_Click;
  67. proxyModeMenu.MenuItems[2].Click += OnProxyMode_Click;
  68. Strip.MenuItems[3].Click += OnSystemProxy_Click;
  69. Strip.MenuItems[4].Click += OnProcessProxy_Click;
  70. openTerminalMenu.MenuItems[0].Click += OpenCmdWithProxySetUp_Click;
  71. openTerminalMenu.MenuItems[1].Click += OpenPowerShellWithProxySetUp_Click;
  72. openTerminalMenu.MenuItems[2].Click += OpenWindowsTerminalWithProxySetUp_Click;
  73. openTerminalMenu.MenuItems[3].Click += OpenFluentTerminalWithProxySetUp_Click;
  74. copyCommandMenu.MenuItems[0].Click += CopyCmdProxySettingCommands_Click;
  75. copyCommandMenu.MenuItems[1].Click += CopyPowerShellProxySettingCommands_Click;
  76. setTelegramProxyMenu.MenuItems[0].Click += SetSocks5ProxyToTelegram_Click;
  77. netFilterMenu.MenuItems[0].Click += InstallNetFilterDriver_Click;
  78. netFilterMenu.MenuItems[1].Click += UninstallNetFilterDriver_Click;
  79. Strip.MenuItems[11].Click += EnableUWPLoopback_Click;
  80. Strip.MenuItems[13].Click += QuitItem_Click;
  81. // 初始化图标
  82. Icon = new NotifyIcon
  83. {
  84. Icon = Resources.Normal,
  85. Visible = false,
  86. Text = "Clash .NET Framework",
  87. ContextMenu = Strip
  88. };
  89. Icon.MouseDown += Icon_MouseDown;
  90. Icon.Visible = true;
  91. }
  92. public void Stop()
  93. {
  94. Icon.MouseDown -= Icon_MouseDown;
  95. Icon.Visible = false;
  96. }
  97. public void SetIcon()
  98. {
  99. if (Global.Settings.ProcessProxy || Global.Settings.SystemProxy)
  100. {
  101. Icon.Icon = Resources.Proxy;
  102. }
  103. else
  104. {
  105. Icon.Icon = Resources.Normal;
  106. }
  107. }
  108. #endregion
  109. #region TrayIcon Event
  110. private async void Icon_MouseDown(object sender, MouseEventArgs e)
  111. {
  112. if (e.Button == MouseButtons.Left)
  113. {
  114. var window = Application.Current.MainWindow;
  115. window.Show();
  116. }
  117. else if (e.Button == MouseButtons.Right)
  118. {
  119. try
  120. {
  121. await InitStatus();
  122. }
  123. catch
  124. {
  125. }
  126. }
  127. }
  128. #endregion
  129. #region Internal Function
  130. private async Task InitStatus()
  131. {
  132. var config = await Global.clashClient.GetClashConfigs();
  133. switch (config.Mode)
  134. {
  135. case ModeType.Direct:
  136. proxyModeMenu.MenuItems[0].Checked = true;
  137. proxyModeMenu.MenuItems[1].Checked = false;
  138. proxyModeMenu.MenuItems[2].Checked = false;
  139. break;
  140. case ModeType.Rule:
  141. proxyModeMenu.MenuItems[0].Checked = false;
  142. proxyModeMenu.MenuItems[1].Checked = true;
  143. proxyModeMenu.MenuItems[2].Checked = false;
  144. break;
  145. case ModeType.Global:
  146. proxyModeMenu.MenuItems[0].Checked = false;
  147. proxyModeMenu.MenuItems[1].Checked = false;
  148. proxyModeMenu.MenuItems[2].Checked =true;
  149. break;
  150. default:
  151. break;
  152. }
  153. Strip.MenuItems[3].Checked = Global.Settings.SystemProxy;
  154. Strip.MenuItems[4].Checked = Global.Settings.ProcessProxy;
  155. }
  156. #endregion
  157. #region MenuItem Click
  158. private void OnDashboard_Click(object sender, EventArgs e)
  159. {
  160. var window = Application.Current.MainWindow;
  161. window.Show();
  162. }
  163. private async void OnProxyMode_Click(object sender, EventArgs e)
  164. {
  165. Dictionary<string, dynamic> dict = new Dictionary<string, dynamic>();
  166. if (sender == proxyModeMenu.MenuItems[0] && !proxyModeMenu.MenuItems[0].Checked)
  167. {
  168. dict.Add("mode", "Direct");
  169. await Global.clashClient.ChangeClashConfigs(dict);
  170. proxyModeMenu.MenuItems[0].Checked = true;
  171. proxyModeMenu.MenuItems[1].Checked = false;
  172. proxyModeMenu.MenuItems[2].Checked = false;
  173. }
  174. else if (sender == proxyModeMenu.MenuItems[1] && !proxyModeMenu.MenuItems[1].Checked)
  175. {
  176. dict.Add("mode", "Rule");
  177. await Global.clashClient.ChangeClashConfigs(dict);
  178. proxyModeMenu.MenuItems[0].Checked = false;
  179. proxyModeMenu.MenuItems[1].Checked = true;
  180. proxyModeMenu.MenuItems[2].Checked = false;
  181. }
  182. else if (sender == proxyModeMenu.MenuItems[2] && !proxyModeMenu.MenuItems[2].Checked)
  183. {
  184. dict.Add("mode", "Global");
  185. await Global.clashClient.ChangeClashConfigs(dict);
  186. proxyModeMenu.MenuItems[0].Checked = false;
  187. proxyModeMenu.MenuItems[1].Checked = false;
  188. proxyModeMenu.MenuItems[2].Checked = true;
  189. }
  190. else
  191. {
  192. // 啥也别干
  193. }
  194. Global.Refresh = true;
  195. }
  196. private void OnSystemProxy_Click(object sender, EventArgs e)
  197. {
  198. if (Strip.MenuItems[3].Checked)
  199. {
  200. using var service = new ProxyService();
  201. service.Direct();
  202. Global.Settings.SystemProxy = false;
  203. }
  204. else
  205. {
  206. using var service = new ProxyService
  207. {
  208. Server = $"127.0.0.1:{Global.ClashMixedPort}",
  209. Bypass = string.Join(@";", ProxyService.LanIp)
  210. };
  211. service.Global();
  212. Global.Settings.SystemProxy = true;
  213. }
  214. Strip.MenuItems[3].Checked = !Strip.MenuItems[3].Checked;
  215. SetIcon();
  216. }
  217. private void OnProcessProxy_Click(object sender, EventArgs e)
  218. {
  219. if (Strip.MenuItems[4].Checked)
  220. {
  221. Global.nfController.Stop();
  222. Global.Settings.ProcessProxy = false;
  223. }
  224. else
  225. {
  226. Global.nfController.Start();
  227. Global.Settings.ProcessProxy = true;
  228. }
  229. Strip.MenuItems[4].Checked = !Strip.MenuItems[4].Checked;
  230. SetIcon();
  231. }
  232. #endregion
  233. #region Open Terminal With Proxy Set Up
  234. private void OpenProcessWithProxySetUp(string name)
  235. {
  236. try
  237. {
  238. var startInfo = new ProcessStartInfo();
  239. // 设置环境变量
  240. startInfo.EnvironmentVariables["http_proxy"] = $"http://127.0.0.1:{Global.ClashMixedPort}";
  241. startInfo.EnvironmentVariables["https_proxy"] = $"http://127.0.0.1:{Global.ClashMixedPort}";
  242. // 否则环境变量无法被设置
  243. startInfo.UseShellExecute = false;
  244. // 设置工作路径
  245. startInfo.WorkingDirectory = Utils.Utils.GetUserDir();
  246. // 文件名
  247. startInfo.FileName = name;
  248. // 开启进程
  249. Process.Start(startInfo);
  250. }
  251. catch
  252. {
  253. }
  254. }
  255. private void OpenCmdWithProxySetUp_Click(object sender, EventArgs e)
  256. {
  257. OpenProcessWithProxySetUp("cmd.exe");
  258. }
  259. private void OpenPowerShellWithProxySetUp_Click(object sender, EventArgs e)
  260. {
  261. OpenProcessWithProxySetUp("powershell.exe");
  262. }
  263. private void OpenWindowsTerminalWithProxySetUp_Click(object sender, EventArgs e)
  264. {
  265. OpenProcessWithProxySetUp("wt.exe");
  266. }
  267. private void OpenFluentTerminalWithProxySetUp_Click(object sender, EventArgs e)
  268. {
  269. OpenProcessWithProxySetUp("flute.exe");
  270. }
  271. #endregion
  272. #region Copy Proxy Setting Commands
  273. private void CopyCmdProxySettingCommands_Click(object sender, EventArgs e)
  274. {
  275. Clipboard.SetText($"set http_proxy=http://127.0.0.1:{Global.ClashMixedPort} & set https_proxy=http://127.0.0.1:{Global.ClashMixedPort}");
  276. }
  277. private void CopyPowerShellProxySettingCommands_Click(object sender, EventArgs e)
  278. {
  279. Clipboard.SetText($"$Env:http_proxy=\"http://127.0.0.1:{Global.ClashMixedPort}\";$Env:https_proxy=\"http://127.0.0.1:{Global.ClashMixedPort}\"");
  280. }
  281. #endregion
  282. #region Set Telegram Proxy
  283. private void SetSocks5ProxyToTelegram_Click(object sender, EventArgs e)
  284. {
  285. Process.Start($"tg://socks?server=127.0.0.1&port={Global.ClashMixedPort}");
  286. }
  287. #endregion
  288. #region NetFilter Driver
  289. private void InstallNetFilterDriver_Click(object sender, EventArgs e)
  290. {
  291. try
  292. {
  293. Global.nfController.InstallDriver();
  294. }
  295. catch
  296. {
  297. }
  298. }
  299. private void UninstallNetFilterDriver_Click(object sender, EventArgs e)
  300. {
  301. try
  302. {
  303. Global.nfController.UninstallDriver();
  304. }
  305. catch
  306. {
  307. }
  308. }
  309. #endregion
  310. #region Enable UWP Loopback
  311. private void EnableUWPLoopback_Click(object sender, EventArgs e)
  312. {
  313. try
  314. {
  315. Process.Start(Path.Combine(Global.ClashDotNetFrameworkDir, "bin\\EnableLoopback.exe"));
  316. }
  317. catch
  318. {
  319. }
  320. }
  321. #endregion
  322. #region Quit
  323. private void QuitItem_Click(object sender, EventArgs e)
  324. {
  325. Application.Current.Shutdown();
  326. }
  327. #endregion
  328. }
  329. }