diff --git a/nuget.config b/nuget.config index f5cdc0be..28c78837 100644 --- a/nuget.config +++ b/nuget.config @@ -1,6 +1,6 @@ - - - - - - + + + + + + diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 429061c0..d2df00fe 100644 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -374,6 +374,16 @@ namespace Shadowsocks.Controller } } + public void SaveHotkeyConfig(HotkeyConfig newConfig) + { + _config.hotkey = newConfig; + SaveConfig(_config); + if (ConfigChanged != null) + { + ConfigChanged(this, new EventArgs()); + } + } + public void UpdateLatency(Server server, TimeSpan latency) { if (_config.availabilityStatistics) @@ -565,6 +575,8 @@ namespace Shadowsocks.Controller File.WriteAllText(PACServer.PAC_FILE, abpContent, Encoding.UTF8); } + #region Memory Management + private void StartReleasingMemory() { _ramThread = new Thread(new ThreadStart(ReleaseMemory)); @@ -581,6 +593,10 @@ namespace Shadowsocks.Controller } } + #endregion + + #region Traffic Statistics + private void StartTrafficStatistics(int queueMaxSize) { traffic = new QueueLast(); @@ -615,5 +631,7 @@ namespace Shadowsocks.Controller } } + #endregion + } } diff --git a/shadowsocks-csharp/Data/cn.txt b/shadowsocks-csharp/Data/cn.txt index 4d30e865..001490ce 100644 --- a/shadowsocks-csharp/Data/cn.txt +++ b/shadowsocks-csharp/Data/cn.txt @@ -27,6 +27,7 @@ Verbose Logging=详细记录日志 Updates...=更新... Check for Updates...=检查更新 Check for Updates at Startup=启动时检查更新 +Edit Hotkeys...=编辑快捷键... About...=关于... Quit=退出 Edit Servers=编辑服务器 @@ -84,6 +85,17 @@ Edit Online PAC URL=编辑在线 PAC 网址 Edit Online PAC URL...=编辑在线 PAC 网址... Please input PAC Url=请输入 PAC 网址 +# HotkeySettings Form + +Switch system proxy=切换系统代理状态 +Switch to PAC mode=切换到PAC模式 +Switch to Global mode=切换到全局模式 +Switch share over LAN=切换局域网共享 +Show Logs=显示日志 +Switch to prev server=切换上个服务器 +Switch to next server=切换下个服务器 +Reg All=注册全部热键 + # Messages Shadowsocks Error: {0}=Shadowsocks 错误: {0} @@ -116,3 +128,5 @@ Unexpected error, shadowsocks will exit. Please report to=非预期错误,Shad Unsupported operating system, use Windows Vista at least.=不支持的操作系统版本,最低需求为Windows Vista。 Proxy request failed=代理请求失败 Proxy handshake failed=代理握手失败 +Register hotkey failed=注册热键失败 +Cannot parse hotkey: {0}=解析热键失败: {0} diff --git a/shadowsocks-csharp/Data/zh_tw.txt b/shadowsocks-csharp/Data/zh_tw.txt index 97d20708..337ce4f3 100644 --- a/shadowsocks-csharp/Data/zh_tw.txt +++ b/shadowsocks-csharp/Data/zh_tw.txt @@ -27,6 +27,7 @@ Verbose Logging=詳細記錄日誌 Updates...=更新... Check for Updates...=檢查更新 Check for Updates at Startup=啟動時檢查更新 +Edit Hotkeys...=編輯熱鍵... About...=關於... Quit=退出 Edit Servers=編輯伺服器 @@ -84,6 +85,17 @@ Edit Online PAC URL=編輯在線 PAC 網址 Edit Online PAC URL...=編輯在線 PAC 網址... Please input PAC Url=請輸入 PAC 網址 +# HotkeySettings Form + +Switch system proxy=切换系統代理狀態 +Switch to PAC mode=切换為PAC模式 +Switch to Global mode=切换為全局模式 +Switch share over LAN=切换局域網共享 +Show Logs=顯示日誌 +Switch to prev server=切换上個伺服器 +Switch to next server=切换下個伺服器 +Reg All=註冊全部熱鍵 + # Messages Shadowsocks Error: {0}=Shadowsocks 錯誤: {0} @@ -116,3 +128,5 @@ Unexpected error, shadowsocks will exit. Please report to=非預期錯誤,Shad Unsupported operating system, use Windows Vista at least.=不支持的作業系統版本,最低需求為Windows Vista。 Proxy request failed=代理請求失敗 Proxy handshake failed=代理握手失敗 +Register hotkey failed=註冊熱鍵失敗 +Cannot parse hotkey: {0}=解析熱鍵失敗: {0} diff --git a/shadowsocks-csharp/Model/Configuration.cs b/shadowsocks-csharp/Model/Configuration.cs index c13d637f..78e63238 100755 --- a/shadowsocks-csharp/Model/Configuration.cs +++ b/shadowsocks-csharp/Model/Configuration.cs @@ -27,6 +27,7 @@ namespace Shadowsocks.Model public bool isVerboseLogging; public LogViewerConfig logViewer; public ProxyConfig proxy; + public HotkeyConfig hotkey; private static string CONFIG_FILE = "gui-config.json"; @@ -60,6 +61,8 @@ namespace Shadowsocks.Model config.logViewer = new LogViewerConfig(); if (config.proxy == null) config.proxy = new ProxyConfig(); + if (config.hotkey == null) + config.hotkey = new HotkeyConfig(); return config; } catch (Exception e) @@ -100,7 +103,7 @@ namespace Shadowsocks.Model } catch (IOException e) { - Console.Error.WriteLine(e); + Logging.LogUsefulException(e); } } diff --git a/shadowsocks-csharp/Model/HotKeyConfig.cs b/shadowsocks-csharp/Model/HotKeyConfig.cs new file mode 100644 index 00000000..2e1d122c --- /dev/null +++ b/shadowsocks-csharp/Model/HotKeyConfig.cs @@ -0,0 +1,33 @@ +using System; + +namespace Shadowsocks.Model +{ + /* + * Format: + * + + * + */ + + [Serializable] + public class HotkeyConfig + { + public string SwitchSystemProxy; + public string ChangeToPac; + public string ChangeToGlobal; + public string SwitchAllowLan; + public string ShowLogs; + public string ServerMoveUp; + public string ServerMoveDown; + + public HotkeyConfig() + { + SwitchSystemProxy = ""; + ChangeToPac = ""; + ChangeToGlobal = ""; + SwitchAllowLan = ""; + ShowLogs = ""; + ServerMoveUp = ""; + ServerMoveDown = ""; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/Program.cs b/shadowsocks-csharp/Program.cs index ce85cd32..99828ff1 100755 --- a/shadowsocks-csharp/Program.cs +++ b/shadowsocks-csharp/Program.cs @@ -39,6 +39,7 @@ namespace Shadowsocks SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); + Application.ApplicationExit += (sender, args) => HotKeys.Destroy(); if (!mutex.WaitOne(0, false)) { @@ -65,6 +66,7 @@ namespace Shadowsocks #endif _controller = new ShadowsocksController(); _viewController = new MenuViewController(_controller); + HotKeys.Init(); _controller.Start(); Application.Run(); } diff --git a/shadowsocks-csharp/Util/Hotkeys.cs b/shadowsocks-csharp/Util/Hotkeys.cs new file mode 100644 index 00000000..f5d8e3d8 --- /dev/null +++ b/shadowsocks-csharp/Util/Hotkeys.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Windows.Forms; +using System.Windows.Input; +using GlobalHotKey; + +namespace Shadowsocks.Util +{ + public static class HotKeys + { + private static HotKeyManager _hotKeyManager; + + public delegate void HotKeyCallBackHandler(); + // map key and corresponding handler function + private static Dictionary _keymap = new Dictionary(); + + public static void Init() + { + _hotKeyManager = new HotKeyManager(); + _hotKeyManager.KeyPressed += HotKeyManagerPressed; + } + + public static void Destroy() => _hotKeyManager.Dispose(); + + private static void HotKeyManagerPressed(object sender, KeyPressedEventArgs e) + { + var hotkey = e.HotKey; + HotKeyCallBackHandler callback; + if (_keymap.TryGetValue(hotkey, out callback)) + callback(); + } + + public static bool IsHotkeyExists( HotKey hotKey ) + { + if (hotKey == null) throw new ArgumentNullException(nameof(hotKey)); + return _keymap.Any( v => v.Key.Equals( hotKey ) ); + } + + public static bool IsCallbackExists( HotKeyCallBackHandler cb, out HotKey hotkey) + { + if (cb == null) throw new ArgumentNullException(nameof(cb)); + try + { + var key = _keymap.First(x => x.Value == cb).Key; + hotkey = key; + return true; + } + catch (InvalidOperationException) + { + // not found + hotkey = null; + return false; + } + } + public static string HotKey2Str( HotKey key ) + { + if (key == null) throw new ArgumentNullException(nameof(key)); + return HotKey2Str( key.Key, key.Modifiers ); + } + + public static string HotKey2Str( Key key, ModifierKeys modifier ) + { + if (!Enum.IsDefined(typeof(Key), key)) + throw new InvalidEnumArgumentException(nameof(key), (int) key, typeof(Key)); + try + { + ModifierKeysConverter mkc = new ModifierKeysConverter(); + var keyStr = Enum.GetName(typeof(Key), key); + var modifierStr = mkc.ConvertToInvariantString(modifier); + + return $"{modifierStr}+{keyStr}"; + } + catch (NotSupportedException) + { + // converter exception + return null; + } + } + + public static HotKey Str2HotKey( string s ) { + try + { + if (s.IsNullOrEmpty()) return null; + int offset = s.LastIndexOf("+", StringComparison.OrdinalIgnoreCase); + if (offset <= 0) return null; + string modifierStr = s.Substring(0, offset).Trim(); + string keyStr = s.Substring(offset + 1).Trim(); + + KeyConverter kc = new KeyConverter(); + ModifierKeysConverter mkc = new ModifierKeysConverter(); + Key key = (Key) kc.ConvertFrom(keyStr.ToUpper()); + ModifierKeys modifier = (ModifierKeys) mkc.ConvertFrom(modifierStr.ToUpper()); + + return new HotKey(key, modifier); + } + catch (NotSupportedException) + { + // converter exception + return null; + } + catch (NullReferenceException) + { + return null; + } + } + + public static bool Regist( HotKey key, HotKeyCallBackHandler callBack ) + { + if (key == null) + throw new ArgumentNullException(nameof(key)); + if (callBack == null) + throw new ArgumentNullException(nameof(callBack)); + try + { + _hotKeyManager.Register(key); + _keymap[key] = callBack; + return true; + } + catch (ArgumentException) + { + // already called this method with the specific hotkey + // return success silently + return true; + } + catch (Win32Exception) + { + // this hotkey already registered by other programs + // notify user to change key + return false; + } + } + + public static bool Regist(Key key, ModifierKeys modifiers, HotKeyCallBackHandler callBack) + { + if (!Enum.IsDefined(typeof(Key), key)) + throw new InvalidEnumArgumentException(nameof(key), (int) key, typeof(Key)); + try + { + var hotkey = _hotKeyManager.Register(key, modifiers); + _keymap[hotkey] = callBack; + return true; + } + catch (ArgumentException) + { + // already called this method with the specific hotkey + // return success silently + return true; + } + catch (Win32Exception) + { + // already registered by other programs + // notify user to change key + return false; + } + } + + public static void UnRegist(HotKey key) + { + if (key == null) + throw new ArgumentNullException(nameof(key)); + _hotKeyManager.Unregister(key); + if(_keymap.ContainsKey(key)) + _keymap.Remove(key); + } + + public static IEnumerable GetChildControls(this Control control) where TControl : Control + { + var children = control.Controls.Count > 0 ? control.Controls.OfType() : Enumerable.Empty(); + return children.SelectMany(c => GetChildControls(c)).Concat(children); + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/Util/Util.cs b/shadowsocks-csharp/Util/Util.cs index b760d3ea..d59cfaf1 100755 --- a/shadowsocks-csharp/Util/Util.cs +++ b/shadowsocks-csharp/Util/Util.cs @@ -1,7 +1,9 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; +using System.Linq; using System.Runtime.InteropServices; using System.Windows.Forms; using Microsoft.Win32; diff --git a/shadowsocks-csharp/View/HotkeySettingsForm.cs b/shadowsocks-csharp/View/HotkeySettingsForm.cs new file mode 100644 index 00000000..bdd2beb3 --- /dev/null +++ b/shadowsocks-csharp/View/HotkeySettingsForm.cs @@ -0,0 +1,406 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Windows.Forms; + +using Shadowsocks.Controller; +using Shadowsocks.Model; +using Shadowsocks.Properties; +using Shadowsocks.Util; + +namespace Shadowsocks.View +{ + public partial class HotkeySettingsForm : Form + { + private ShadowsocksController _controller; + + // this is a copy of configuration that we are working on + private HotkeyConfig _modifiedConfig; + + private StringBuilder _sb = new StringBuilder(); + + private IEnumerable _allTextBoxes; + + private static Label _lb = null; + private static HotKeys.HotKeyCallBackHandler _callBack = null; + + public HotkeySettingsForm(ShadowsocksController controller) + { + InitializeComponent(); + UpdateTexts(); + this.Icon = Icon.FromHandle(Resources.ssw128.GetHicon()); + + _controller = controller; + _controller.ConfigChanged += controller_ConfigChanged; + + LoadCurrentConfiguration(); + + // get all textboxes belong to this form + _allTextBoxes = HotKeys.GetChildControls(this.tableLayoutPanel1); + if (!_allTextBoxes.Any()) throw new Exception("Cannot get all textboxes"); + } + + private void controller_ConfigChanged(object sender, EventArgs e) + { + LoadCurrentConfiguration(); + } + + private void LoadCurrentConfiguration() + { + _modifiedConfig = _controller.GetConfigurationCopy().hotkey; + LoadConfiguration(_modifiedConfig); + } + + private void LoadConfiguration(HotkeyConfig config) + { + SwitchSystemProxyTextBox.Text = config.SwitchSystemProxy; + ChangeToPacTextBox.Text = config.ChangeToPac; + ChangeToGlobalTextBox.Text = config.ChangeToGlobal; + SwitchAllowLanTextBox.Text = config.SwitchAllowLan; + ShowLogsTextBox.Text = config.ShowLogs; + ServerMoveUpTextBox.Text = config.ServerMoveUp; + ServerMoveDownTextBox.Text = config.ServerMoveDown; + } + + private void UpdateTexts() + { + // I18N stuff + SwitchSystemProxyLabel.Text = I18N.GetString("Switch system proxy"); + ChangeToPacLabel.Text = I18N.GetString("Switch to PAC mode"); + ChangeToGlobalLabel.Text = I18N.GetString("Switch to Global mode"); + SwitchAllowLanLabel.Text = I18N.GetString("Switch share over LAN"); + ShowLogsLabel.Text = I18N.GetString("Show Logs"); + ServerMoveUpLabel.Text = I18N.GetString("Switch to prev server"); + ServerMoveDownLabel.Text = I18N.GetString("Switch to next server"); + btnOK.Text = I18N.GetString("OK"); + btnCancel.Text = I18N.GetString("Cancel"); + btnRegisterAll.Text = I18N.GetString("Reg All"); + this.Text = I18N.GetString("Edit Hotkeys..."); + } + + /// + /// Capture hotkey - Press key + /// + private void HotkeyDown(object sender, KeyEventArgs e) + { + _sb.Length = 0; + //Combination key only + if (e.Modifiers != 0) + { + // XXX: Hotkey parsing depends on the sequence, more specifically, ModifierKeysConverter. + // Windows key is reserved by operating system, we deny this key. + if (e.Control) + { + _sb.Append("Ctrl+"); + } + if (e.Alt) + { + _sb.Append("Alt+"); + } + if (e.Shift) + { + _sb.Append("Shift+"); + } + + Keys keyvalue = (Keys) e.KeyValue; + if ((keyvalue >= Keys.PageUp && keyvalue <= Keys.Down) || + (keyvalue >= Keys.A && keyvalue <= Keys.Z) || + (keyvalue >= Keys.F1 && keyvalue <= Keys.F12)) + { + _sb.Append(e.KeyCode); + } + else if (keyvalue >= Keys.D0 && keyvalue <= Keys.D9) + { + _sb.Append('D').Append((char) e.KeyValue); + } + else if (keyvalue >= Keys.NumPad0 && keyvalue <= Keys.NumPad9) + { + _sb.Append("NumPad").Append((char) (e.KeyValue - 48)); + } + } + ((TextBox) sender).Text = _sb.ToString(); + } + + /// + /// Capture hotkey - Release key + /// + private void HotkeyUp(object sender, KeyEventArgs e) + { + TextBox tb = sender as TextBox; + string content = tb.Text.TrimEnd(); + if (content.Length >= 1 && content[content.Length - 1] == '+') + { + tb.Text = ""; + } + } + + private void TextBox_TextChanged(object sender, EventArgs e) + { + TextBox tb = sender as TextBox; + + if (tb.Text == "") + { + // unreg + UnregHotkey(tb); + } + } + + private void UnregHotkey(TextBox tb) + { + + PrepareForHotkey(tb, out _callBack, out _lb); + + UnregPrevHotkey(_callBack); + } + + private void CancelButton_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void OKButton_Click(object sender, EventArgs e) + { + // try to register, notify to change settings if failed + foreach (var tb in _allTextBoxes) + { + if (tb.Text.IsNullOrEmpty()) + { + continue; + } + if (!TryRegHotkey(tb)) + { + MessageBox.Show(I18N.GetString("Register hotkey failed")); + return; + } + } + + // All check passed, saving + SaveConfig(); + this.Close(); + } + + private void RegisterAllButton_Click(object sender, EventArgs e) + { + foreach (var tb in _allTextBoxes) + { + if (tb.Text.IsNullOrEmpty()) + { + continue; + } + TryRegHotkey(tb); + } + } + + private bool TryRegHotkey(TextBox tb) + { + var hotkey = HotKeys.Str2HotKey(tb.Text); + if (hotkey == null) + { + MessageBox.Show(string.Format(I18N.GetString("Cannot parse hotkey: {0}"), tb.Text)); + tb.Clear(); + return false; + } + + PrepareForHotkey(tb, out _callBack, out _lb); + + UnregPrevHotkey(_callBack); + + // try to register keys + // if already registered by other progs + // notify to change + + // use the corresponding label color to indicate + // reg result. + // Green: not occupied by others and operation succeed + // Yellow: already registered by other program and need action: disable by clear the content + // or change to another one + // Transparent without color: first run or empty config + + bool regResult = HotKeys.Regist(hotkey, _callBack); + _lb.BackColor = regResult ? Color.Green : Color.Yellow; + return regResult; + } + + private static void UnregPrevHotkey(HotKeys.HotKeyCallBackHandler cb) + { + GlobalHotKey.HotKey prevHotKey; + if (HotKeys.IsCallbackExists(cb, out prevHotKey)) + { + // unregister previous one + HotKeys.UnRegist(prevHotKey); + } + } + + private void SaveConfig() + { + _modifiedConfig.SwitchSystemProxy = SwitchSystemProxyTextBox.Text; + _modifiedConfig.ChangeToPac = ChangeToPacTextBox.Text; + _modifiedConfig.ChangeToGlobal = ChangeToGlobalTextBox.Text; + _modifiedConfig.SwitchAllowLan = SwitchAllowLanTextBox.Text; + _modifiedConfig.ShowLogs = ShowLogsTextBox.Text; + _modifiedConfig.ServerMoveUp = ServerMoveUpTextBox.Text; + _modifiedConfig.ServerMoveDown = ServerMoveDownTextBox.Text; + _controller.SaveHotkeyConfig(_modifiedConfig); + } + + #region Callbacks + + private void SwitchSystemProxyCallback() + { + bool enabled = _controller.GetConfigurationCopy().enabled; + _controller.ToggleEnable(!enabled); + } + + private void ChangeToPacCallback() + { + bool enabled = _controller.GetConfigurationCopy().enabled; + if (enabled == false) return; + _controller.ToggleGlobal(false); + } + + private void ChangeToGlobalCallback() + { + bool enabled = _controller.GetConfigurationCopy().enabled; + if (enabled == false) return; + _controller.ToggleGlobal(true); + } + + private void SwitchAllowLanCallback() + { + var status = _controller.GetConfigurationCopy().shareOverLan; + _controller.ToggleShareOverLAN(!status); + } + + private void ShowLogsCallback() + { + // Get the current MenuViewController in this program via reflection + FieldInfo fi = Assembly.GetExecutingAssembly().GetType("Shadowsocks.Program") + .GetField("_viewController", + BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.IgnoreCase); + // To retrieve the value of a static field, pass null here + var mvc = fi.GetValue(null) as MenuViewController; + mvc.ShowLogForm_HotKey(); + } + + private void ServerMoveUpCallback() + { + int currIndex; + int serverCount; + GetCurrServerInfo(out currIndex, out serverCount); + if (currIndex - 1 < 0) + { + // revert to last server + currIndex = serverCount - 1; + } + else + { + currIndex -= 1; + } + _controller.SelectServerIndex(currIndex); + } + + private void ServerMoveDownCallback() + { + int currIndex; + int serverCount; + GetCurrServerInfo(out currIndex, out serverCount); + if (currIndex + 1 == serverCount) + { + // revert to first server + currIndex = 0; + } + else + { + currIndex += 1; + } + _controller.SelectServerIndex(currIndex); + } + + private void GetCurrServerInfo(out int currIndex, out int serverCount) + { + var currConfig = _controller.GetCurrentConfiguration(); + currIndex = currConfig.index; + serverCount = currConfig.configs.Count; + } + + #endregion + + #region Prepare hotkey + + /// + /// Find correct callback and corresponding label + /// + /// + /// + /// + private void PrepareForHotkey(TextBox tb, out HotKeys.HotKeyCallBackHandler cb, out Label lb) + { + /* + * XXX: The labelName, TextBoxName and callbackName + * must follow this rule to make use of reflection + * + * + */ + if (tb == null) + throw new ArgumentNullException(nameof(tb)); + + var pos = tb.Name.LastIndexOf("TextBox", StringComparison.OrdinalIgnoreCase); + var rawName = tb.Name.Substring(0, pos); + var labelName = rawName + "Label"; + var callbackName = rawName + "Callback"; + + var callback = GetDelegateViaMethodName(this.GetType(), callbackName); + if (callback == null) + { + throw new Exception($"{callbackName} not found"); + } + cb = callback as HotKeys.HotKeyCallBackHandler; + + object label = GetFieldViaName(this.GetType(), labelName, this); + if (label == null) + { + throw new Exception($"{labelName} not found"); + } + lb = label as Label; + } + + /// + /// + /// + /// from which type + /// field name + /// pass null if static field + /// + private static object GetFieldViaName(Type type, string name, object obj) + { + if (type == null) throw new ArgumentNullException(nameof(type)); + if (name.IsNullOrEmpty()) throw new ArgumentException(nameof(name)); + // In general, TextBoxes and Labels are private + FieldInfo fi = type.GetField(name, + BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Static); + return fi == null ? null : fi.GetValue(obj); + } + + /// + /// Create hotkey callback handler delegate based on callback name + /// + /// + /// + /// + private Delegate GetDelegateViaMethodName(Type type, string methodname) + { + if (type == null) throw new ArgumentNullException(nameof(type)); + if (methodname.IsNullOrEmpty()) throw new ArgumentException(nameof(methodname)); + //HotkeySettingsForm form = new HotkeySettingsForm(_controller); + Type delegateType = Type.GetType("Shadowsocks.Util.HotKeys").GetNestedType("HotKeyCallBackHandler"); + MethodInfo dynMethod = type.GetMethod(methodname, + BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase); + return dynMethod == null ? null : Delegate.CreateDelegate(delegateType, this, dynMethod); + } + + #endregion + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/View/HotkeySettingsForm.designer.cs b/shadowsocks-csharp/View/HotkeySettingsForm.designer.cs new file mode 100644 index 00000000..5367fc88 --- /dev/null +++ b/shadowsocks-csharp/View/HotkeySettingsForm.designer.cs @@ -0,0 +1,354 @@ +namespace Shadowsocks.View +{ + partial class HotkeySettingsForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnRegisterAll = new System.Windows.Forms.Button(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.SwitchSystemProxyLabel = new System.Windows.Forms.Label(); + this.ChangeToPacLabel = new System.Windows.Forms.Label(); + this.ChangeToGlobalLabel = new System.Windows.Forms.Label(); + this.SwitchAllowLanLabel = new System.Windows.Forms.Label(); + this.ShowLogsLabel = new System.Windows.Forms.Label(); + this.ServerMoveUpLabel = new System.Windows.Forms.Label(); + this.ServerMoveDownLabel = new System.Windows.Forms.Label(); + this.SwitchSystemProxyTextBox = new System.Windows.Forms.TextBox(); + this.ChangeToPacTextBox = new System.Windows.Forms.TextBox(); + this.ChangeToGlobalTextBox = new System.Windows.Forms.TextBox(); + this.SwitchAllowLanTextBox = new System.Windows.Forms.TextBox(); + this.ShowLogsTextBox = new System.Windows.Forms.TextBox(); + this.ServerMoveUpTextBox = new System.Windows.Forms.TextBox(); + this.ServerMoveDownTextBox = new System.Windows.Forms.TextBox(); + flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); + flowLayoutPanel1.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // flowLayoutPanel1 + // + this.tableLayoutPanel1.SetColumnSpan(flowLayoutPanel1, 2); + flowLayoutPanel1.Controls.Add(this.btnOK); + flowLayoutPanel1.Controls.Add(this.btnCancel); + flowLayoutPanel1.Controls.Add(this.btnRegisterAll); + flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.BottomUp; + flowLayoutPanel1.Location = new System.Drawing.Point(0, 227); + flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0); + flowLayoutPanel1.Name = "flowLayoutPanel1"; + flowLayoutPanel1.Padding = new System.Windows.Forms.Padding(0, 0, 16, 0); + flowLayoutPanel1.RightToLeft = System.Windows.Forms.RightToLeft.Yes; + flowLayoutPanel1.Size = new System.Drawing.Size(475, 44); + flowLayoutPanel1.TabIndex = 6; + // + // btnOK + // + this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.btnOK.Location = new System.Drawing.Point(381, 10); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(75, 31); + this.btnOK.TabIndex = 0; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + this.btnOK.Click += new System.EventHandler(this.OKButton_Click); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(300, 10); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(75, 31); + this.btnCancel.TabIndex = 1; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.CancelButton_Click); + // + // btnRegisterAll + // + this.btnRegisterAll.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnRegisterAll.Location = new System.Drawing.Point(219, 10); + this.btnRegisterAll.Name = "btnRegisterAll"; + this.btnRegisterAll.Size = new System.Drawing.Size(75, 31); + this.btnRegisterAll.TabIndex = 2; + this.btnRegisterAll.Text = "Reg All"; + this.btnRegisterAll.UseVisualStyleBackColor = true; + this.btnRegisterAll.Click += new System.EventHandler(this.RegisterAllButton_Click); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.SwitchSystemProxyLabel, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.ChangeToPacLabel, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.ChangeToGlobalLabel, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.SwitchAllowLanLabel, 0, 3); + this.tableLayoutPanel1.Controls.Add(this.ShowLogsLabel, 0, 4); + this.tableLayoutPanel1.Controls.Add(this.ServerMoveUpLabel, 0, 5); + this.tableLayoutPanel1.Controls.Add(this.ServerMoveDownLabel, 0, 6); + this.tableLayoutPanel1.Controls.Add(flowLayoutPanel1, 0, 7); + this.tableLayoutPanel1.Controls.Add(this.SwitchSystemProxyTextBox, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.ChangeToPacTextBox, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.ChangeToGlobalTextBox, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.SwitchAllowLanTextBox, 1, 3); + this.tableLayoutPanel1.Controls.Add(this.ShowLogsTextBox, 1, 4); + this.tableLayoutPanel1.Controls.Add(this.ServerMoveUpTextBox, 1, 5); + this.tableLayoutPanel1.Controls.Add(this.ServerMoveDownTextBox, 1, 6); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 8; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.16667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.16667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.16667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.16667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.16667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.77778F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.38889F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(475, 271); + this.tableLayoutPanel1.TabIndex = 0; + // + // SwitchSystemProxyLabel + // + this.SwitchSystemProxyLabel.AutoSize = true; + this.SwitchSystemProxyLabel.Dock = System.Windows.Forms.DockStyle.Right; + this.SwitchSystemProxyLabel.Location = new System.Drawing.Point(25, 0); + this.SwitchSystemProxyLabel.Margin = new System.Windows.Forms.Padding(8, 0, 8, 0); + this.SwitchSystemProxyLabel.Name = "SwitchSystemProxyLabel"; + this.SwitchSystemProxyLabel.Size = new System.Drawing.Size(147, 32); + this.SwitchSystemProxyLabel.TabIndex = 0; + this.SwitchSystemProxyLabel.Text = "Enable System Proxy"; + this.SwitchSystemProxyLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // ChangeToPacLabel + // + this.ChangeToPacLabel.AutoSize = true; + this.ChangeToPacLabel.Dock = System.Windows.Forms.DockStyle.Right; + this.ChangeToPacLabel.Location = new System.Drawing.Point(135, 32); + this.ChangeToPacLabel.Margin = new System.Windows.Forms.Padding(8, 0, 8, 0); + this.ChangeToPacLabel.Name = "ChangeToPacLabel"; + this.ChangeToPacLabel.Size = new System.Drawing.Size(37, 32); + this.ChangeToPacLabel.TabIndex = 1; + this.ChangeToPacLabel.Text = "PAC"; + this.ChangeToPacLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // ChangeToGlobalLabel + // + this.ChangeToGlobalLabel.AutoSize = true; + this.ChangeToGlobalLabel.Dock = System.Windows.Forms.DockStyle.Right; + this.ChangeToGlobalLabel.Location = new System.Drawing.Point(119, 64); + this.ChangeToGlobalLabel.Margin = new System.Windows.Forms.Padding(8, 0, 8, 0); + this.ChangeToGlobalLabel.Name = "ChangeToGlobalLabel"; + this.ChangeToGlobalLabel.Size = new System.Drawing.Size(53, 32); + this.ChangeToGlobalLabel.TabIndex = 2; + this.ChangeToGlobalLabel.Text = "Global"; + this.ChangeToGlobalLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // SwitchAllowLanLabel + // + this.SwitchAllowLanLabel.AutoSize = true; + this.SwitchAllowLanLabel.Dock = System.Windows.Forms.DockStyle.Right; + this.SwitchAllowLanLabel.Location = new System.Drawing.Point(8, 96); + this.SwitchAllowLanLabel.Margin = new System.Windows.Forms.Padding(8, 0, 8, 0); + this.SwitchAllowLanLabel.Name = "SwitchAllowLanLabel"; + this.SwitchAllowLanLabel.Size = new System.Drawing.Size(164, 32); + this.SwitchAllowLanLabel.TabIndex = 3; + this.SwitchAllowLanLabel.Text = "Allow Clients from LAN"; + this.SwitchAllowLanLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // ShowLogsLabel + // + this.ShowLogsLabel.AutoSize = true; + this.ShowLogsLabel.Dock = System.Windows.Forms.DockStyle.Right; + this.ShowLogsLabel.Location = new System.Drawing.Point(82, 128); + this.ShowLogsLabel.Margin = new System.Windows.Forms.Padding(8, 0, 8, 0); + this.ShowLogsLabel.Name = "ShowLogsLabel"; + this.ShowLogsLabel.Size = new System.Drawing.Size(90, 32); + this.ShowLogsLabel.TabIndex = 4; + this.ShowLogsLabel.Text = "Show Logs..."; + this.ShowLogsLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // ServerMoveUpLabel + // + this.ServerMoveUpLabel.AutoSize = true; + this.ServerMoveUpLabel.Dock = System.Windows.Forms.DockStyle.Right; + this.ServerMoveUpLabel.Location = new System.Drawing.Point(103, 160); + this.ServerMoveUpLabel.Margin = new System.Windows.Forms.Padding(8, 0, 8, 0); + this.ServerMoveUpLabel.Name = "ServerMoveUpLabel"; + this.ServerMoveUpLabel.Size = new System.Drawing.Size(69, 34); + this.ServerMoveUpLabel.TabIndex = 4; + this.ServerMoveUpLabel.Text = "Move up"; + this.ServerMoveUpLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // ServerMoveDownLabel + // + this.ServerMoveDownLabel.AutoSize = true; + this.ServerMoveDownLabel.Dock = System.Windows.Forms.DockStyle.Right; + this.ServerMoveDownLabel.Location = new System.Drawing.Point(81, 194); + this.ServerMoveDownLabel.Margin = new System.Windows.Forms.Padding(8, 0, 8, 0); + this.ServerMoveDownLabel.Name = "ServerMoveDownLabel"; + this.ServerMoveDownLabel.Size = new System.Drawing.Size(91, 33); + this.ServerMoveDownLabel.TabIndex = 4; + this.ServerMoveDownLabel.Text = "Move Down"; + this.ServerMoveDownLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // SwitchSystemProxyTextBox + // + this.SwitchSystemProxyTextBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.SwitchSystemProxyTextBox.Location = new System.Drawing.Point(183, 3); + this.SwitchSystemProxyTextBox.Margin = new System.Windows.Forms.Padding(3, 3, 16, 3); + this.SwitchSystemProxyTextBox.Name = "SwitchSystemProxyTextBox"; + this.SwitchSystemProxyTextBox.ReadOnly = true; + this.SwitchSystemProxyTextBox.Size = new System.Drawing.Size(276, 25); + this.SwitchSystemProxyTextBox.TabIndex = 7; + this.SwitchSystemProxyTextBox.TextChanged += new System.EventHandler(this.TextBox_TextChanged); + this.SwitchSystemProxyTextBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.HotkeyDown); + this.SwitchSystemProxyTextBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.HotkeyUp); + // + // ChangeToPacTextBox + // + this.ChangeToPacTextBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.ChangeToPacTextBox.Location = new System.Drawing.Point(183, 35); + this.ChangeToPacTextBox.Margin = new System.Windows.Forms.Padding(3, 3, 16, 3); + this.ChangeToPacTextBox.Name = "ChangeToPacTextBox"; + this.ChangeToPacTextBox.ReadOnly = true; + this.ChangeToPacTextBox.Size = new System.Drawing.Size(276, 25); + this.ChangeToPacTextBox.TabIndex = 8; + this.ChangeToPacTextBox.TextChanged += new System.EventHandler(this.TextBox_TextChanged); + this.ChangeToPacTextBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.HotkeyDown); + this.ChangeToPacTextBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.HotkeyUp); + // + // ChangeToGlobalTextBox + // + this.ChangeToGlobalTextBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.ChangeToGlobalTextBox.Location = new System.Drawing.Point(183, 67); + this.ChangeToGlobalTextBox.Margin = new System.Windows.Forms.Padding(3, 3, 16, 3); + this.ChangeToGlobalTextBox.Name = "ChangeToGlobalTextBox"; + this.ChangeToGlobalTextBox.ReadOnly = true; + this.ChangeToGlobalTextBox.Size = new System.Drawing.Size(276, 25); + this.ChangeToGlobalTextBox.TabIndex = 9; + this.ChangeToGlobalTextBox.TextChanged += new System.EventHandler(this.TextBox_TextChanged); + this.ChangeToGlobalTextBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.HotkeyDown); + this.ChangeToGlobalTextBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.HotkeyUp); + // + // SwitchAllowLanTextBox + // + this.SwitchAllowLanTextBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.SwitchAllowLanTextBox.Location = new System.Drawing.Point(183, 99); + this.SwitchAllowLanTextBox.Margin = new System.Windows.Forms.Padding(3, 3, 16, 3); + this.SwitchAllowLanTextBox.Name = "SwitchAllowLanTextBox"; + this.SwitchAllowLanTextBox.ReadOnly = true; + this.SwitchAllowLanTextBox.Size = new System.Drawing.Size(276, 25); + this.SwitchAllowLanTextBox.TabIndex = 10; + this.SwitchAllowLanTextBox.TextChanged += new System.EventHandler(this.TextBox_TextChanged); + this.SwitchAllowLanTextBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.HotkeyDown); + this.SwitchAllowLanTextBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.HotkeyUp); + // + // ShowLogsTextBox + // + this.ShowLogsTextBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.ShowLogsTextBox.Location = new System.Drawing.Point(183, 131); + this.ShowLogsTextBox.Margin = new System.Windows.Forms.Padding(3, 3, 16, 3); + this.ShowLogsTextBox.Name = "ShowLogsTextBox"; + this.ShowLogsTextBox.ReadOnly = true; + this.ShowLogsTextBox.Size = new System.Drawing.Size(276, 25); + this.ShowLogsTextBox.TabIndex = 11; + this.ShowLogsTextBox.TextChanged += new System.EventHandler(this.TextBox_TextChanged); + this.ShowLogsTextBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.HotkeyDown); + this.ShowLogsTextBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.HotkeyUp); + // + // ServerMoveUpTextBox + // + this.ServerMoveUpTextBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.ServerMoveUpTextBox.Location = new System.Drawing.Point(183, 163); + this.ServerMoveUpTextBox.Margin = new System.Windows.Forms.Padding(3, 3, 16, 3); + this.ServerMoveUpTextBox.Name = "ServerMoveUpTextBox"; + this.ServerMoveUpTextBox.ReadOnly = true; + this.ServerMoveUpTextBox.Size = new System.Drawing.Size(276, 25); + this.ServerMoveUpTextBox.TabIndex = 12; + this.ServerMoveUpTextBox.TextChanged += new System.EventHandler(this.TextBox_TextChanged); + this.ServerMoveUpTextBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.HotkeyDown); + this.ServerMoveUpTextBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.HotkeyUp); + // + // ServerMoveDownTextBox + // + this.ServerMoveDownTextBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.ServerMoveDownTextBox.Location = new System.Drawing.Point(183, 197); + this.ServerMoveDownTextBox.Margin = new System.Windows.Forms.Padding(3, 3, 16, 3); + this.ServerMoveDownTextBox.Name = "ServerMoveDownTextBox"; + this.ServerMoveDownTextBox.ReadOnly = true; + this.ServerMoveDownTextBox.Size = new System.Drawing.Size(276, 25); + this.ServerMoveDownTextBox.TabIndex = 13; + this.ServerMoveDownTextBox.TextChanged += new System.EventHandler(this.TextBox_TextChanged); + this.ServerMoveDownTextBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.HotkeyDown); + this.ServerMoveDownTextBox.KeyUp += new System.Windows.Forms.KeyEventHandler(this.HotkeyUp); + // + // HotkeySettingsForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 19F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(475, 271); + this.Controls.Add(this.tableLayoutPanel1); + this.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "HotkeySettingsForm"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Edit Hotkeys..."; + flowLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + private System.Windows.Forms.Label SwitchSystemProxyLabel; + private System.Windows.Forms.Label ChangeToPacLabel; + private System.Windows.Forms.Label ChangeToGlobalLabel; + private System.Windows.Forms.Label SwitchAllowLanLabel; + private System.Windows.Forms.Label ShowLogsLabel; + private System.Windows.Forms.Label ServerMoveUpLabel; + private System.Windows.Forms.Label ServerMoveDownLabel; + private System.Windows.Forms.Button btnOK; + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.TextBox ShowLogsTextBox; + private System.Windows.Forms.TextBox SwitchAllowLanTextBox; + private System.Windows.Forms.TextBox ChangeToGlobalTextBox; + private System.Windows.Forms.TextBox ChangeToPacTextBox; + private System.Windows.Forms.TextBox SwitchSystemProxyTextBox; + private System.Windows.Forms.TextBox ServerMoveUpTextBox; + private System.Windows.Forms.TextBox ServerMoveDownTextBox; + private System.Windows.Forms.Button btnRegisterAll; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/View/HotkeySettingsForm.resx b/shadowsocks-csharp/View/HotkeySettingsForm.resx new file mode 100644 index 00000000..f5b19983 --- /dev/null +++ b/shadowsocks-csharp/View/HotkeySettingsForm.resx @@ -0,0 +1,183 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 115b0c79..4aa270b1 100644 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -49,10 +49,12 @@ namespace Shadowsocks.View private MenuItem editOnlinePACItem; private MenuItem autoCheckUpdatesToggleItem; private MenuItem proxyItem; + private MenuItem hotKeyItem; private MenuItem VerboseLoggingToggleItem; private ConfigForm configForm; private ProxyForm proxyForm; private LogForm logForm; + private HotkeySettingsForm hotkeySettingsForm; private string _urlToOpen; public MenuViewController(ShadowsocksController controller) @@ -276,6 +278,7 @@ namespace Shadowsocks.View new MenuItem("-"), CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)), this.VerboseLoggingToggleItem = CreateMenuItem( "Verbose Logging", new EventHandler(this.VerboseLoggingToggleItem_Click) ), + this.hotKeyItem = CreateMenuItem("Edit Hotkeys...", new EventHandler(this.hotKeyItem_Click)), CreateMenuGroup("Updates...", new MenuItem[] { CreateMenuItem("Check for Updates...", new EventHandler(this.checkUpdatesItem_Click)), new MenuItem("-"), @@ -466,6 +469,21 @@ namespace Shadowsocks.View } } + private void ShowHotKeySettingsForm() + { + if (hotkeySettingsForm != null) + { + hotkeySettingsForm.Activate(); + } + else + { + hotkeySettingsForm = new HotkeySettingsForm(controller); + hotkeySettingsForm.Show(); + hotkeySettingsForm.Activate(); + hotkeySettingsForm.FormClosed += hotkeySettingsForm_FormClosed; + } + } + private void ShowLogForm() { if (logForm != null) @@ -505,6 +523,12 @@ namespace Shadowsocks.View Utils.ReleaseMemory(true); } + void hotkeySettingsForm_FormClosed(object sender, FormClosedEventArgs e) + { + hotkeySettingsForm = null; + Utils.ReleaseMemory(true); + } + private void Config_Click(object sender, EventArgs e) { ShowConfigForm(); @@ -811,9 +835,19 @@ namespace Shadowsocks.View ShowProxyForm(); } + private void hotKeyItem_Click(object sender, EventArgs e) + { + ShowHotKeySettingsForm(); + } + private void ShowLogItem_Click(object sender, EventArgs e) { ShowLogForm(); } + + public void ShowLogForm_HotKey() + { + ShowLogForm(); + } } } diff --git a/shadowsocks-csharp/packages.config b/shadowsocks-csharp/packages.config index ea2a7bce..8b1d7274 100644 --- a/shadowsocks-csharp/packages.config +++ b/shadowsocks-csharp/packages.config @@ -3,6 +3,7 @@ + \ No newline at end of file diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index c8c47596..1e7a5392 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -65,6 +65,10 @@ app.manifest + + 3rd\GlobalHotKey.1.1.0\lib\GlobalHotKey.dll + True + @@ -139,6 +143,7 @@ + @@ -178,6 +183,7 @@ + @@ -200,6 +206,12 @@ CalculationControl.cs + + Form + + + HotkeySettingsForm.cs + Form @@ -240,6 +252,9 @@ CalculationControl.cs + + HotkeySettingsForm.cs + LogForm.cs diff --git a/test/UnitTest.cs b/test/UnitTest.cs index 6fa4f21d..6364dba2 100755 --- a/test/UnitTest.cs +++ b/test/UnitTest.cs @@ -2,6 +2,9 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Shadowsocks.Controller; using Shadowsocks.Encryption; +using Shadowsocks.Util; +using GlobalHotKey; +using System.Windows.Input; using System.Threading; using System.Collections.Generic; @@ -22,6 +25,32 @@ namespace test Assert.IsTrue(UpdateChecker.Asset.CompareVersion("1.3.2", "1.3.1") > 0); } + [ TestMethod ] + public void TestHotKey2Str() { + Assert.AreEqual( "Ctrl+A", HotKeys.HotKey2Str( Key.A, ModifierKeys.Control ) ); + Assert.AreEqual( "Ctrl+Alt+D2", HotKeys.HotKey2Str( Key.D2, (ModifierKeys.Alt | ModifierKeys.Control) ) ); + Assert.AreEqual("Ctrl+Alt+Shift+NumPad7", HotKeys.HotKey2Str(Key.NumPad7, (ModifierKeys.Alt|ModifierKeys.Control|ModifierKeys.Shift))); + Assert.AreEqual( "Ctrl+Alt+Shift+F6", HotKeys.HotKey2Str( Key.F6, (ModifierKeys.Alt|ModifierKeys.Control|ModifierKeys.Shift))); + Assert.AreNotEqual("Ctrl+Shift+Alt+F6", HotKeys.HotKey2Str(Key.F6, (ModifierKeys.Alt | ModifierKeys.Control | ModifierKeys.Shift))); + } + + [TestMethod] + public void TestStr2HotKey() + { + Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+A").Equals(new HotKey(Key.A, ModifierKeys.Control))); + Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Alt+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt)))); + Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Shift+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Shift)))); + Assert.IsTrue(HotKeys.Str2HotKey("Ctrl+Alt+Shift+A").Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt| ModifierKeys.Shift)))); + HotKey testKey0 = HotKeys.Str2HotKey("Ctrl+Alt+Shift+A"); + Assert.IsTrue(testKey0 != null && testKey0.Equals(new HotKey(Key.A, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift)))); + HotKey testKey1 = HotKeys.Str2HotKey("Ctrl+Alt+Shift+F2"); + Assert.IsTrue(testKey1 != null && testKey1.Equals(new HotKey(Key.F2, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift)))); + HotKey testKey2 = HotKeys.Str2HotKey("Ctrl+Shift+Alt+D7"); + Assert.IsTrue(testKey2 != null && testKey2.Equals(new HotKey(Key.D7, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift)))); + HotKey testKey3 = HotKeys.Str2HotKey("Ctrl+Shift+Alt+NumPad7"); + Assert.IsTrue(testKey3 != null && testKey3.Equals(new HotKey(Key.NumPad7, (ModifierKeys.Control | ModifierKeys.Alt | ModifierKeys.Shift)))); + } + [TestMethod] public void TestMD5() { diff --git a/test/test.csproj b/test/test.csproj index d1c3fa2e..2d261cfb 100755 --- a/test/test.csproj +++ b/test/test.csproj @@ -35,10 +35,15 @@ + + ..\shadowsocks-csharp\3rd\GlobalHotKey.1.1.0\lib\GlobalHotKey.dll + True + +