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
+
+