@@ -0,0 +1,103 @@ | |||||
using System.Reflection; | |||||
using Shadowsocks.View; | |||||
namespace Shadowsocks.Controller.Hotkeys | |||||
{ | |||||
public class HotkeyCallbacks | |||||
{ | |||||
public static HotkeyCallbacks Instance { get; private set; } | |||||
public static void InitInstance(ShadowsocksController controller) | |||||
{ | |||||
if (Instance != null) | |||||
{ | |||||
return; | |||||
} | |||||
Instance = new HotkeyCallbacks(controller); | |||||
} | |||||
private readonly ShadowsocksController _controller; | |||||
private HotkeyCallbacks(ShadowsocksController controller) | |||||
{ | |||||
_controller = controller; | |||||
} | |||||
#region Callbacks | |||||
private void SwitchSystemProxyCallback() | |||||
{ | |||||
bool enabled = _controller.GetConfigurationCopy().enabled; | |||||
_controller.ToggleEnable(!enabled); | |||||
} | |||||
private void SwitchProxyModeCallback() | |||||
{ | |||||
var config = _controller.GetConfigurationCopy(); | |||||
if (config.enabled == false) return; | |||||
var currStatus = config.global; | |||||
_controller.ToggleGlobal(!currStatus); | |||||
} | |||||
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 | |||||
} | |||||
} |
@@ -1,179 +1,181 @@ | |||||
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<HotKey, HotKeyCallBackHandler> _keymap = new Dictionary<HotKey, HotKeyCallBackHandler>(); | |||||
public static void Init() | |||||
{ | |||||
_hotKeyManager = new HotKeyManager(); | |||||
_hotKeyManager.KeyPressed += HotKeyManagerPressed; | |||||
} | |||||
public static void Destroy() | |||||
{ | |||||
_hotKeyManager.KeyPressed -= HotKeyManagerPressed; | |||||
_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<TControl> GetChildControls<TControl>(this Control control) where TControl : Control | |||||
{ | |||||
var children = control.Controls.Count > 0 ? control.Controls.OfType<TControl>() : Enumerable.Empty<TControl>(); | |||||
return children.SelectMany(c => GetChildControls<TControl>(c)).Concat(children); | |||||
} | |||||
} | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.ComponentModel; | |||||
using System.Linq; | |||||
using System.Windows.Forms; | |||||
using System.Windows.Input; | |||||
using GlobalHotKey; | |||||
namespace Shadowsocks.Controller.Hotkeys | |||||
{ | |||||
public static class HotKeys | |||||
{ | |||||
private static HotKeyManager _hotKeyManager; | |||||
public delegate void HotKeyCallBackHandler(); | |||||
// map key and corresponding handler function | |||||
private static Dictionary<HotKey, HotKeyCallBackHandler> _keymap = new Dictionary<HotKey, HotKeyCallBackHandler>(); | |||||
public static void Init(ShadowsocksController controller) | |||||
{ | |||||
_hotKeyManager = new HotKeyManager(); | |||||
_hotKeyManager.KeyPressed += HotKeyManagerPressed; | |||||
HotkeyCallbacks.InitInstance(controller); | |||||
} | |||||
public static void Destroy() | |||||
{ | |||||
_hotKeyManager.KeyPressed -= HotKeyManagerPressed; | |||||
_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<TControl> GetChildControls<TControl>(this Control control) where TControl : Control | |||||
{ | |||||
var children = control.Controls.Count > 0 ? control.Controls.OfType<TControl>() : Enumerable.Empty<TControl>(); | |||||
return children.SelectMany(c => GetChildControls<TControl>(c)).Concat(children); | |||||
} | |||||
} | |||||
} | } |
@@ -6,6 +6,7 @@ using System.Windows.Forms; | |||||
using Microsoft.Win32; | using Microsoft.Win32; | ||||
using Shadowsocks.Controller; | using Shadowsocks.Controller; | ||||
using Shadowsocks.Controller.Hotkeys; | |||||
using Shadowsocks.Util; | using Shadowsocks.Util; | ||||
using Shadowsocks.View; | using Shadowsocks.View; | ||||
@@ -7,6 +7,7 @@ using System.Text; | |||||
using System.Windows.Forms; | using System.Windows.Forms; | ||||
using Shadowsocks.Controller; | using Shadowsocks.Controller; | ||||
using Shadowsocks.Controller.Hotkeys; | |||||
using Shadowsocks.Model; | using Shadowsocks.Model; | ||||
using Shadowsocks.Properties; | using Shadowsocks.Properties; | ||||
using Shadowsocks.Util; | using Shadowsocks.Util; | ||||
@@ -243,81 +244,7 @@ namespace Shadowsocks.View | |||||
_controller.SaveHotkeyConfig(_modifiedConfig); | _controller.SaveHotkeyConfig(_modifiedConfig); | ||||
} | } | ||||
#region Callbacks | |||||
private void SwitchSystemProxyCallback() | |||||
{ | |||||
bool enabled = _controller.GetConfigurationCopy().enabled; | |||||
_controller.ToggleEnable(!enabled); | |||||
} | |||||
private void SwitchProxyModeCallback() | |||||
{ | |||||
var config = _controller.GetConfigurationCopy(); | |||||
if (config.enabled == false) return; | |||||
var currStatus = config.global; | |||||
_controller.ToggleGlobal(!currStatus); | |||||
} | |||||
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 | #region Prepare hotkey | ||||
@@ -343,7 +270,7 @@ namespace Shadowsocks.View | |||||
var labelName = rawName + "Label"; | var labelName = rawName + "Label"; | ||||
var callbackName = rawName + "Callback"; | var callbackName = rawName + "Callback"; | ||||
var callback = GetDelegateViaMethodName(this.GetType(), callbackName); | |||||
var callback = GetDelegateViaMethodName(callbackName); | |||||
if (callback == null) | if (callback == null) | ||||
{ | { | ||||
throw new Exception($"{callbackName} not found"); | throw new Exception($"{callbackName} not found"); | ||||
@@ -381,15 +308,12 @@ namespace Shadowsocks.View | |||||
/// <param name="type"></param> | /// <param name="type"></param> | ||||
/// <param name="methodname"></param> | /// <param name="methodname"></param> | ||||
/// <returns></returns> | /// <returns></returns> | ||||
private Delegate GetDelegateViaMethodName(Type type, string methodname) | |||||
private Delegate GetDelegateViaMethodName(string methodname) | |||||
{ | { | ||||
if (type == null) throw new ArgumentNullException(nameof(type)); | |||||
if (methodname.IsNullOrEmpty()) throw new ArgumentException(nameof(methodname)); | 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, | |||||
MethodInfo dynMethod = typeof(HotkeyCallbacks).GetMethod(methodname, | |||||
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase); | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase); | ||||
return dynMethod == null ? null : Delegate.CreateDelegate(delegateType, this, dynMethod); | |||||
return dynMethod == null ? null : Delegate.CreateDelegate(typeof(HotKeys.HotKeyCallBackHandler), HotkeyCallbacks.Instance, dynMethod); | |||||
} | } | ||||
#endregion | #endregion | ||||
@@ -139,6 +139,7 @@ | |||||
<Compile Include="3rd\zxing\ResultPoint.cs" /> | <Compile Include="3rd\zxing\ResultPoint.cs" /> | ||||
<Compile Include="3rd\zxing\ResultPointCallback.cs" /> | <Compile Include="3rd\zxing\ResultPointCallback.cs" /> | ||||
<Compile Include="3rd\zxing\WriterException.cs" /> | <Compile Include="3rd\zxing\WriterException.cs" /> | ||||
<Compile Include="Controller\System\Hotkeys\HotkeyCallbacks.cs" /> | |||||
<Compile Include="Model\HotKeyConfig.cs" /> | <Compile Include="Model\HotKeyConfig.cs" /> | ||||
<Compile Include="Model\ProxyConfig.cs" /> | <Compile Include="Model\ProxyConfig.cs" /> | ||||
<Compile Include="Properties\Settings.Designer.cs"> | <Compile Include="Properties\Settings.Designer.cs"> | ||||
@@ -186,7 +187,7 @@ | |||||
<Compile Include="Proxy\Socks5Proxy.cs" /> | <Compile Include="Proxy\Socks5Proxy.cs" /> | ||||
<Compile Include="Settings.cs" /> | <Compile Include="Settings.cs" /> | ||||
<Compile Include="StringEx.cs" /> | <Compile Include="StringEx.cs" /> | ||||
<Compile Include="Util\Hotkeys.cs" /> | |||||
<Compile Include="Controller\System\Hotkeys\Hotkeys.cs" /> | |||||
<Compile Include="Util\ProcessManagement\Job.cs" /> | <Compile Include="Util\ProcessManagement\Job.cs" /> | ||||
<Compile Include="Util\ProcessManagement\ThreadUtil.cs" /> | <Compile Include="Util\ProcessManagement\ThreadUtil.cs" /> | ||||
<Compile Include="Encryption\RNG.cs" /> | <Compile Include="Encryption\RNG.cs" /> | ||||
@@ -2,11 +2,11 @@ | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||
using Shadowsocks.Controller; | using Shadowsocks.Controller; | ||||
using Shadowsocks.Encryption; | using Shadowsocks.Encryption; | ||||
using Shadowsocks.Util; | |||||
using GlobalHotKey; | using GlobalHotKey; | ||||
using System.Windows.Input; | using System.Windows.Input; | ||||
using System.Threading; | using System.Threading; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using Shadowsocks.Controller.Hotkeys; | |||||
namespace test | namespace test | ||||
{ | { | ||||