@@ -23,9 +23,9 @@ namespace Shadowsocks.PAC | |||
public class GeositeUpdater : IEnableLogger | |||
{ | |||
public event EventHandler<GeositeResultEventArgs> UpdateCompleted; | |||
public event EventHandler<GeositeResultEventArgs>? UpdateCompleted; | |||
public event ErrorEventHandler Error; | |||
public event ErrorEventHandler? Error; | |||
private readonly string DATABASE_PATH; | |||
@@ -230,7 +230,7 @@ var __RULES__ = {JsonSerializer.Serialize(ruleLines, jsonSerializerOptions)}; | |||
List<string> valid_lines = new List<string>(); | |||
using (var stringReader = new StringReader(content)) | |||
{ | |||
for (string line = stringReader.ReadLine(); line != null; line = stringReader.ReadLine()) | |||
for (string? line = stringReader.ReadLine(); line != null; line = stringReader.ReadLine()) | |||
{ | |||
if (string.IsNullOrWhiteSpace(line) || line.StartsWith("!") || line.StartsWith("[")) | |||
continue; | |||
@@ -189,13 +189,14 @@ Connection: Close | |||
private void SendCallback(IAsyncResult ar) | |||
{ | |||
Socket conn = (Socket)ar.AsyncState; | |||
Socket? conn = ar.AsyncState as Socket; | |||
try | |||
{ | |||
conn.Shutdown(SocketShutdown.Send); | |||
conn?.Shutdown(SocketShutdown.Send); | |||
} | |||
catch | |||
{ } | |||
{ | |||
} | |||
} | |||
private string GetPACAddress(IPEndPoint localEndPoint, bool useSocks) => $"{(useSocks ? "SOCKS5" : "PROXY")} {localEndPoint};"; | |||
@@ -2,6 +2,7 @@ | |||
<PropertyGroup> | |||
<TargetFramework>netcoreapp3.1</TargetFramework> | |||
<Nullable>enable</Nullable> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
@@ -1,91 +0,0 @@ | |||
using NLog; | |||
using Shadowsocks.Controller.Hotkeys; | |||
using System; | |||
using System.Windows.Forms; | |||
namespace Shadowsocks.WPF.Behaviors | |||
{ | |||
static class HotkeyReg | |||
{ | |||
private static Logger logger = LogManager.GetCurrentClassLogger(); | |||
public static void RegAllHotkeys() | |||
{ | |||
var hotkeyConfig = Program.MainController.GetCurrentConfiguration().hotkey; | |||
if (hotkeyConfig == null || !hotkeyConfig.RegHotkeysAtStartup) | |||
return; | |||
// if any of the hotkey reg fail, undo everything | |||
if (RegHotkeyFromString(hotkeyConfig.SwitchSystemProxy, "SwitchSystemProxyCallback") | |||
&& RegHotkeyFromString(hotkeyConfig.SwitchSystemProxyMode, "SwitchSystemProxyModeCallback") | |||
&& RegHotkeyFromString(hotkeyConfig.SwitchAllowLan, "SwitchAllowLanCallback") | |||
&& RegHotkeyFromString(hotkeyConfig.ShowLogs, "ShowLogsCallback") | |||
&& RegHotkeyFromString(hotkeyConfig.ServerMoveUp, "ServerMoveUpCallback") | |||
&& RegHotkeyFromString(hotkeyConfig.ServerMoveDown, "ServerMoveDownCallback") | |||
) | |||
{ | |||
// success | |||
} | |||
else | |||
{ | |||
RegHotkeyFromString("", "SwitchSystemProxyCallback"); | |||
RegHotkeyFromString("", "SwitchSystemProxyModeCallback"); | |||
RegHotkeyFromString("", "SwitchAllowLanCallback"); | |||
RegHotkeyFromString("", "ShowLogsCallback"); | |||
RegHotkeyFromString("", "ServerMoveUpCallback"); | |||
RegHotkeyFromString("", "ServerMoveDownCallback"); | |||
MessageBox.Show(I18N.GetString("Register hotkey failed"), I18N.GetString("Shadowsocks")); | |||
} | |||
} | |||
public static bool RegHotkeyFromString(string hotkeyStr, string callbackName, Action<RegResult> onComplete = null) | |||
{ | |||
var _callback = HotkeyCallbacks.GetCallback(callbackName); | |||
if (_callback == null) | |||
{ | |||
throw new Exception($"{callbackName} not found"); | |||
} | |||
var callback = _callback as HotKeys.HotKeyCallBackHandler; | |||
if (string.IsNullOrEmpty(hotkeyStr)) | |||
{ | |||
HotKeys.UnregExistingHotkey(callback); | |||
onComplete?.Invoke(RegResult.UnregSuccess); | |||
return true; | |||
} | |||
else | |||
{ | |||
var hotkey = HotKeys.Str2HotKey(hotkeyStr); | |||
if (hotkey == null) | |||
{ | |||
logger.Error($"Cannot parse hotkey: {hotkeyStr}"); | |||
onComplete?.Invoke(RegResult.ParseError); | |||
return false; | |||
} | |||
else | |||
{ | |||
bool regResult = (HotKeys.RegHotkey(hotkey, callback)); | |||
if (regResult) | |||
{ | |||
onComplete?.Invoke(RegResult.RegSuccess); | |||
} | |||
else | |||
{ | |||
onComplete?.Invoke(RegResult.RegFailure); | |||
} | |||
return regResult; | |||
} | |||
} | |||
} | |||
public enum RegResult | |||
{ | |||
RegSuccess, | |||
RegFailure, | |||
ParseError, | |||
UnregSuccess, | |||
//UnregFailure | |||
} | |||
} | |||
} |
@@ -1,114 +0,0 @@ | |||
using System; | |||
using System.Reflection; | |||
namespace Shadowsocks.Controller.Hotkeys | |||
{ | |||
public class HotkeyCallbacks | |||
{ | |||
public static void InitInstance(ShadowsocksController controller) | |||
{ | |||
if (Instance != null) | |||
{ | |||
return; | |||
} | |||
Instance = new HotkeyCallbacks(controller); | |||
} | |||
/// <summary> | |||
/// Create hotkey callback handler delegate based on callback name | |||
/// </summary> | |||
/// <param name="methodname"></param> | |||
/// <returns></returns> | |||
public static Delegate GetCallback(string methodname) | |||
{ | |||
if (string.IsNullOrEmpty(methodname)) throw new ArgumentException(nameof(methodname)); | |||
MethodInfo dynMethod = typeof(HotkeyCallbacks).GetMethod(methodname, | |||
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase); | |||
return dynMethod == null ? null : Delegate.CreateDelegate(typeof(HotKeys.HotKeyCallBackHandler), Instance, dynMethod); | |||
} | |||
#region Singleton | |||
private static HotkeyCallbacks Instance { get; set; } | |||
private readonly ShadowsocksController _controller; | |||
private HotkeyCallbacks(ShadowsocksController controller) | |||
{ | |||
_controller = controller; | |||
} | |||
#endregion | |||
#region Callbacks | |||
private void SwitchSystemProxyCallback() | |||
{ | |||
bool enabled = _controller.GetCurrentConfiguration().enabled; | |||
_controller.ToggleEnable(!enabled); | |||
} | |||
private void SwitchSystemProxyModeCallback() | |||
{ | |||
var config = _controller.GetCurrentConfiguration(); | |||
if (config.enabled) | |||
_controller.ToggleGlobal(!config.global); | |||
} | |||
private void SwitchAllowLanCallback() | |||
{ | |||
var status = _controller.GetCurrentConfiguration().shareOverLan; | |||
_controller.ToggleShareOverLAN(!status); | |||
} | |||
private void ShowLogsCallback() | |||
{ | |||
Program.MenuController.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,174 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.ComponentModel; | |||
using System.Linq; | |||
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 RegHotkey(HotKey hotkey, HotKeyCallBackHandler callback) | |||
{ | |||
UnregExistingHotkey(callback); | |||
return Register(hotkey, callback); | |||
} | |||
public static bool UnregExistingHotkey(HotKeys.HotKeyCallBackHandler cb) | |||
{ | |||
HotKey existingHotKey; | |||
if (IsCallbackExists(cb, out existingHotKey)) | |||
{ | |||
// unregister existing one | |||
Unregister(existingHotKey); | |||
return true; | |||
} | |||
else | |||
{ | |||
return false; | |||
} | |||
} | |||
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)); | |||
if (_keymap.Any(v => v.Value == cb)) | |||
{ | |||
hotkey = _keymap.First(v => v.Value == cb).Key; | |||
return true; | |||
} | |||
else | |||
{ | |||
hotkey = null; | |||
return false; | |||
} | |||
} | |||
#region Converters | |||
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 (string.IsNullOrEmpty(s)) 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; | |||
} | |||
} | |||
#endregion | |||
private static bool Register(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; | |||
} | |||
} | |||
private static void Unregister(HotKey key) | |||
{ | |||
if (key == null) | |||
throw new ArgumentNullException(nameof(key)); | |||
_hotKeyManager.Unregister(key); | |||
if(_keymap.ContainsKey(key)) | |||
_keymap.Remove(key); | |||
} | |||
} | |||
} |
@@ -1,143 +0,0 @@ | |||
using Shadowsocks.Net.SystemProxy; | |||
using System; | |||
using System.ComponentModel; | |||
using System.Net; | |||
using System.Net.Sockets; | |||
namespace NLog | |||
{ | |||
public static class LoggerExtension | |||
{ | |||
// for key, iv, etc... | |||
public static void Dump(this Logger logger, string tag, ReadOnlySpan<byte> arr) | |||
{ | |||
logger.Dump(tag, arr.ToArray(), arr.Length); | |||
} | |||
public static void Dump(this Logger logger, string tag, byte[] arr, int length = -1) | |||
{ | |||
if (arr == null) logger.Trace($@" | |||
{tag}: | |||
(null) | |||
"); | |||
if (length == -1) length = arr.Length; | |||
if (!logger.IsTraceEnabled) return; | |||
string hex = BitConverter.ToString(arr.AsSpan(0, Math.Min(arr.Length, length)).ToArray()).Replace("-", ""); | |||
string content = $@" | |||
{tag}: | |||
{hex} | |||
"; | |||
logger.Trace(content); | |||
} | |||
// for cipher and plain text, so we can use openssl to test | |||
public static void DumpBase64(this Logger logger, string tag, ReadOnlySpan<byte> arr) | |||
{ | |||
logger.DumpBase64(tag, arr.ToArray(), arr.Length); | |||
} | |||
public static void DumpBase64(this Logger logger, string tag, byte[] arr, int length = -1) | |||
{ | |||
if (arr == null) logger.Trace($@" | |||
{tag}: | |||
(null) | |||
"); | |||
if (length == -1) length = arr.Length; | |||
if (!logger.IsTraceEnabled) return; | |||
string hex = Convert.ToBase64String(arr.AsSpan(0, Math.Min(arr.Length, length)).ToArray()); | |||
string content = $@" | |||
{tag}: | |||
{hex} | |||
"; | |||
logger.Trace(content); | |||
} | |||
public static void Debug(this Logger logger, EndPoint local, EndPoint remote, int len, string header = null, string tailer = null) | |||
{ | |||
if (logger.IsDebugEnabled) | |||
{ | |||
if (header == null && tailer == null) | |||
logger.Debug($"{local} => {remote} (size={len})"); | |||
else if (header == null && tailer != null) | |||
logger.Debug($"{local} => {remote} (size={len}), {tailer}"); | |||
else if (header != null && tailer == null) | |||
logger.Debug($"{header}: {local} => {remote} (size={len})"); | |||
else | |||
logger.Debug($"{header}: {local} => {remote} (size={len}), {tailer}"); | |||
} | |||
} | |||
public static void Debug(this Logger logger, Socket sock, int len, string header = null, string tailer = null) | |||
{ | |||
if (logger.IsDebugEnabled) | |||
logger.Debug(sock.LocalEndPoint, sock.RemoteEndPoint, len, header, tailer); | |||
} | |||
public static void LogUsefulException(this Logger logger, Exception e) | |||
{ | |||
// just log useful exceptions, not all of them | |||
if (e is SocketException se) | |||
{ | |||
if (se.SocketErrorCode == SocketError.ConnectionAborted) | |||
{ | |||
// closed by browser when sending | |||
// normally happens when download is canceled or a tab is closed before page is loaded | |||
} | |||
else if (se.SocketErrorCode == SocketError.ConnectionReset) | |||
{ | |||
// received rst | |||
} | |||
else if (se.SocketErrorCode == SocketError.NotConnected) | |||
{ | |||
// The application tried to send or receive data, and the System.Net.Sockets.Socket is not connected. | |||
} | |||
else if (se.SocketErrorCode == SocketError.HostUnreachable) | |||
{ | |||
// There is no network route to the specified host. | |||
} | |||
else if (se.SocketErrorCode == SocketError.TimedOut) | |||
{ | |||
// The connection attempt timed out, or the connected host has failed to respond. | |||
} | |||
else | |||
{ | |||
logger.Warn(e); | |||
} | |||
} | |||
else if (e is ObjectDisposedException) | |||
{ | |||
} | |||
else if (e is Win32Exception ex) | |||
{ | |||
// Win32Exception (0x80004005): A 32 bit processes cannot access modules of a 64 bit process. | |||
if ((uint)ex.ErrorCode != 0x80004005) | |||
logger.Warn(e); | |||
} | |||
else if (e is ProxyException pe) | |||
{ | |||
switch (pe.Type) | |||
{ | |||
case ProxyExceptionType.FailToRun: | |||
case ProxyExceptionType.QueryReturnMalformed: | |||
case ProxyExceptionType.SysproxyExitError: | |||
logger.Error($"sysproxy - {pe.Type}:{pe.Message}"); | |||
break; | |||
case ProxyExceptionType.QueryReturnEmpty: | |||
case ProxyExceptionType.Unspecific: | |||
logger.Error($"sysproxy - {pe.Type}"); | |||
break; | |||
} | |||
} | |||
else | |||
{ | |||
logger.Warn(e); | |||
} | |||
} | |||
} | |||
} |
@@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. | |||
--> | |||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
<PropertyGroup> | |||
<Configuration>Debug</Configuration> | |||
<Configuration>Release</Configuration> | |||
<Platform>Any CPU</Platform> | |||
<PublishDir>bin\Release\netcoreapp3.1\publish\</PublishDir> | |||
<PublishProtocol>FileSystem</PublishProtocol> | |||
@@ -0,0 +1,105 @@ | |||
//------------------------------------------------------------------------------ | |||
// <auto-generated> | |||
// This code was generated by a tool. | |||
// Runtime Version:4.0.30319.42000 | |||
// | |||
// Changes to this file may cause incorrect behavior and will be lost if | |||
// the code is regenerated. | |||
// </auto-generated> | |||
//------------------------------------------------------------------------------ | |||
namespace Shadowsocks.WPF.Properties { | |||
using System; | |||
/// <summary> | |||
/// A strongly-typed resource class, for looking up localized strings, etc. | |||
/// </summary> | |||
// This class was auto-generated by the StronglyTypedResourceBuilder | |||
// class via a tool like ResGen or Visual Studio. | |||
// To add or remove a member, edit your .ResX file then rerun ResGen | |||
// with the /str option, or rebuild your VS project. | |||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] | |||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] | |||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] | |||
internal class Resources { | |||
private static global::System.Resources.ResourceManager resourceMan; | |||
private static global::System.Globalization.CultureInfo resourceCulture; | |||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] | |||
internal Resources() { | |||
} | |||
/// <summary> | |||
/// Returns the cached ResourceManager instance used by this class. | |||
/// </summary> | |||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | |||
internal static global::System.Resources.ResourceManager ResourceManager { | |||
get { | |||
if (object.ReferenceEquals(resourceMan, null)) { | |||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Shadowsocks.WPF.Properties.Resources", typeof(Resources).Assembly); | |||
resourceMan = temp; | |||
} | |||
return resourceMan; | |||
} | |||
} | |||
/// <summary> | |||
/// Overrides the current thread's CurrentUICulture property for all | |||
/// resource lookups using this strongly typed resource class. | |||
/// </summary> | |||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] | |||
internal static global::System.Globalization.CultureInfo Culture { | |||
get { | |||
return resourceCulture; | |||
} | |||
set { | |||
resourceCulture = value; | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?> | |||
///<!-- Warning: Configuration may reset after shadowsocks upgrade. --> | |||
///<!-- If you messed it up, delete this file and Shadowsocks will create a new one. --> | |||
///<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> | |||
/// <targets> | |||
/// <!-- This line is managed by Shadowsocks. Do not modify it unless you know what you are doing.--> | |||
/// <target name="file" xsi:type="File" fileName="ss_win_temp\shadowsocks [rest of string was truncated]";. | |||
/// </summary> | |||
internal static string NLog { | |||
get { | |||
return ResourceManager.GetString("NLog", resourceCulture); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized string similar to listen-address __PRIVOXY_BIND_IP__:__PRIVOXY_BIND_PORT__ | |||
///toggle 0 | |||
///logfile ss_privoxy.log | |||
///show-on-task-bar 0 | |||
///activity-animation 0 | |||
///forward-socks5 / __SOCKS_HOST__:__SOCKS_PORT__ . | |||
///max-client-connections 2048 | |||
///hide-console | |||
///. | |||
/// </summary> | |||
internal static string privoxy_conf { | |||
get { | |||
return ResourceManager.GetString("privoxy_conf", resourceCulture); | |||
} | |||
} | |||
/// <summary> | |||
/// Looks up a localized resource of type System.Byte[]. | |||
/// </summary> | |||
internal static byte[] privoxy_exe { | |||
get { | |||
object obj = ResourceManager.GetObject("privoxy_exe", resourceCulture); | |||
return ((byte[])(obj)); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,130 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<root> | |||
<!-- | |||
Microsoft ResX Schema | |||
Version 2.0 | |||
The primary goals of this format is to allow a simple XML format | |||
that is mostly human readable. The generation and parsing of the | |||
various data types are done through the TypeConverter classes | |||
associated with the data types. | |||
Example: | |||
... ado.net/XML headers & schema ... | |||
<resheader name="resmimetype">text/microsoft-resx</resheader> | |||
<resheader name="version">2.0</resheader> | |||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> | |||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> | |||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> | |||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> | |||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> | |||
<value>[base64 mime encoded serialized .NET Framework object]</value> | |||
</data> | |||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> | |||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> | |||
<comment>This is a comment</comment> | |||
</data> | |||
There are any number of "resheader" rows that contain simple | |||
name/value pairs. | |||
Each data row contains a name, and value. The row also contains a | |||
type or mimetype. Type corresponds to a .NET class that support | |||
text/value conversion through the TypeConverter architecture. | |||
Classes that don't support this are serialized and stored with the | |||
mimetype set. | |||
The mimetype is used for serialized objects, and tells the | |||
ResXResourceReader how to depersist the object. This is currently not | |||
extensible. For a given mimetype the value must be set accordingly: | |||
Note - application/x-microsoft.net.object.binary.base64 is the format | |||
that the ResXResourceWriter will generate, however the reader can | |||
read any of the formats listed below. | |||
mimetype: application/x-microsoft.net.object.binary.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.soap.base64 | |||
value : The object must be serialized with | |||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter | |||
: and then encoded with base64 encoding. | |||
mimetype: application/x-microsoft.net.object.bytearray.base64 | |||
value : The object must be serialized into a byte array | |||
: using a System.ComponentModel.TypeConverter | |||
: and then encoded with base64 encoding. | |||
--> | |||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> | |||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> | |||
<xsd:element name="root" msdata:IsDataSet="true"> | |||
<xsd:complexType> | |||
<xsd:choice maxOccurs="unbounded"> | |||
<xsd:element name="metadata"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" use="required" type="xsd:string" /> | |||
<xsd:attribute name="type" type="xsd:string" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="assembly"> | |||
<xsd:complexType> | |||
<xsd:attribute name="alias" type="xsd:string" /> | |||
<xsd:attribute name="name" type="xsd:string" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="data"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> | |||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> | |||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> | |||
<xsd:attribute ref="xml:space" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
<xsd:element name="resheader"> | |||
<xsd:complexType> | |||
<xsd:sequence> | |||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> | |||
</xsd:sequence> | |||
<xsd:attribute name="name" type="xsd:string" use="required" /> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:choice> | |||
</xsd:complexType> | |||
</xsd:element> | |||
</xsd:schema> | |||
<resheader name="resmimetype"> | |||
<value>text/microsoft-resx</value> | |||
</resheader> | |||
<resheader name="version"> | |||
<value>2.0</value> | |||
</resheader> | |||
<resheader name="reader"> | |||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<resheader name="writer"> | |||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</resheader> | |||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> | |||
<data name="NLog" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\Resources\NLog.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value> | |||
</data> | |||
<data name="privoxy_conf" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\Resources\privoxy_conf.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value> | |||
</data> | |||
<data name="privoxy_exe" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||
<value>..\Resources\privoxy.exe.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | |||
</data> | |||
</root> |
@@ -11,15 +11,46 @@ | |||
<Version>1.0.0</Version> | |||
<ApplicationIcon>Assets\shadowsocks.ico</ApplicationIcon> | |||
<NoWin32Manifest>true</NoWin32Manifest> | |||
<Nullable>enable</Nullable> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<None Remove="Resources\NLog.config" /> | |||
<None Remove="Resources\privoxy.exe.gz" /> | |||
<None Remove="Resources\privoxy_conf.txt" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-Bold.ttf" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-BoldItalic.ttf" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-ExtraLight.ttf" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-ExtraLightItalic.ttf" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-Italic.ttf" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-Light.ttf" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-LightItalic.ttf" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-Medium.ttf" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-MediumItalic.ttf" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-Regular.ttf" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-SemiBold.ttf" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-SemiBoldItalic.ttf" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-Thin.ttf" /> | |||
<None Remove="Resources\RobotoMono\RobotoMono-ThinItalic.ttf" /> | |||
<None Remove="Resources\shadowsocks.ico" /> | |||
<None Remove="Resources\ss128.pdn" /> | |||
<None Remove="Resources\ss32.pdn" /> | |||
<None Remove="Resources\ss32Fill.png" /> | |||
<None Remove="Resources\ss32In.png" /> | |||
<None Remove="Resources\ss32Out.png" /> | |||
<None Remove="Resources\ss32Outline.png" /> | |||
<None Remove="Resources\ssw128.png" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<PackageReference Include="MaterialDesignThemes" Version="3.2.0" /> | |||
<PackageReference Include="MdXaml" Version="1.6.0" /> | |||
<PackageReference Include="OxyPlot.Wpf" Version="2.0.0" /> | |||
<PackageReference Include="ReactiveUI.Events.WPF" Version="12.1.1" /> | |||
<PackageReference Include="ReactiveUI.Fody" Version="12.1.1" /> | |||
<PackageReference Include="ReactiveUI.Events.WPF" Version="12.1.5" /> | |||
<PackageReference Include="ReactiveUI.Fody" Version="12.1.5" /> | |||
<PackageReference Include="ReactiveUI.Validation" Version="1.8.6" /> | |||
<PackageReference Include="ReactiveUI.WPF" Version="12.1.1" /> | |||
<PackageReference Include="ReactiveUI.WPF" Version="12.1.5" /> | |||
<PackageReference Include="Splat.NLog" Version="9.6.1" /> | |||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20371.2" /> | |||
<PackageReference Include="WPFLocalizeExtension" Version="3.8.0" /> | |||
<PackageReference Include="ZXing.Net" Version="0.16.6" /> | |||
@@ -31,6 +62,11 @@ | |||
<AutoGen>True</AutoGen> | |||
<DependentUpon>Strings.resx</DependentUpon> | |||
</Compile> | |||
<Compile Update="Properties\Resources.Designer.cs"> | |||
<DesignTime>True</DesignTime> | |||
<AutoGen>True</AutoGen> | |||
<DependentUpon>Resources.resx</DependentUpon> | |||
</Compile> | |||
</ItemGroup> | |||
<ItemGroup> | |||
@@ -38,15 +74,43 @@ | |||
<Generator>ResXFileCodeGenerator</Generator> | |||
<LastGenOutput>Strings.Designer.cs</LastGenOutput> | |||
</EmbeddedResource> | |||
<EmbeddedResource Update="Properties\Resources.resx"> | |||
<Generator>ResXFileCodeGenerator</Generator> | |||
<LastGenOutput>Resources.Designer.cs</LastGenOutput> | |||
</EmbeddedResource> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Folder Include="Resources\" /> | |||
<ProjectReference Include="..\Shadowsocks.Net\Shadowsocks.Net.csproj" /> | |||
<ProjectReference Include="..\Shadowsocks\Shadowsocks.csproj" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\Shadowsocks.Net\Shadowsocks.Net.csproj" /> | |||
<ProjectReference Include="..\Shadowsocks\Shadowsocks.csproj" /> | |||
<Resource Include="Resources\NLog.config" /> | |||
<Resource Include="Resources\privoxy.exe.gz" /> | |||
<Resource Include="Resources\privoxy_conf.txt" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-Bold.ttf" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-BoldItalic.ttf" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-ExtraLight.ttf" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-ExtraLightItalic.ttf" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-Italic.ttf" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-Light.ttf" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-LightItalic.ttf" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-Medium.ttf" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-MediumItalic.ttf" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-Regular.ttf" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-SemiBold.ttf" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-SemiBoldItalic.ttf" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-Thin.ttf" /> | |||
<Resource Include="Resources\RobotoMono\RobotoMono-ThinItalic.ttf" /> | |||
<Resource Include="Resources\shadowsocks.ico" /> | |||
<Resource Include="Resources\ss128.pdn" /> | |||
<Resource Include="Resources\ss32.pdn" /> | |||
<Resource Include="Resources\ss32Fill.png" /> | |||
<Resource Include="Resources\ss32In.png" /> | |||
<Resource Include="Resources\ss32Out.png" /> | |||
<Resource Include="Resources\ss32Outline.png" /> | |||
<Resource Include="Resources\ssw128.png" /> | |||
</ItemGroup> | |||
</Project> |
@@ -1,189 +0,0 @@ | |||
using ReactiveUI; | |||
using ReactiveUI.Fody.Helpers; | |||
using Shadowsocks.Controller; | |||
using Shadowsocks.Model; | |||
using Shadowsocks.View; | |||
using System.Reactive; | |||
using System.Text; | |||
using System.Windows.Input; | |||
namespace Shadowsocks.WPF.ViewModels | |||
{ | |||
public class HotkeysViewModel : ReactiveObject | |||
{ | |||
public HotkeysViewModel() | |||
{ | |||
_config = Program.MainController.GetCurrentConfiguration(); | |||
_controller = Program.MainController; | |||
_menuViewController = Program.MenuController; | |||
HotkeySystemProxy = _config.hotkey.SwitchSystemProxy; | |||
HotkeyProxyMode = _config.hotkey.SwitchSystemProxyMode; | |||
HotkeyAllowLan = _config.hotkey.SwitchAllowLan; | |||
HotkeyOpenLogs = _config.hotkey.ShowLogs; | |||
HotkeySwitchPrev = _config.hotkey.ServerMoveUp; | |||
HotkeySwitchNext = _config.hotkey.ServerMoveDown; | |||
RegisterAtStartup = _config.hotkey.RegHotkeysAtStartup; | |||
HotkeySystemProxyStatus = "✔"; | |||
HotkeyProxyModeStatus = "✔"; | |||
HotkeyAllowLanStatus = "✔"; | |||
HotkeyOpenLogsStatus = "✔"; | |||
HotkeySwitchPrevStatus = "✔"; | |||
HotkeySwitchNextStatus = "✔"; | |||
RegisterAll = ReactiveCommand.Create(() => RegisterAllAndUpdateStatus()); | |||
Save = ReactiveCommand.Create(() => RegisterAllAndUpdateStatus(true)); | |||
Cancel = ReactiveCommand.Create(_menuViewController.CloseHotkeysWindow); | |||
} | |||
private readonly Configuration _config; | |||
private readonly ShadowsocksController _controller; | |||
private readonly MenuViewController _menuViewController; | |||
public ReactiveCommand<Unit, Unit> RegisterAll { get; } | |||
public ReactiveCommand<Unit, Unit> Save { get; } | |||
public ReactiveCommand<Unit, Unit> Cancel { get; } | |||
[Reactive] | |||
public string HotkeySystemProxy { get; set; } | |||
[Reactive] | |||
public string HotkeyProxyMode { get; set; } | |||
[Reactive] | |||
public string HotkeyAllowLan { get; set; } | |||
[Reactive] | |||
public string HotkeyOpenLogs { get; set; } | |||
[Reactive] | |||
public string HotkeySwitchPrev { get; set; } | |||
[Reactive] | |||
public string HotkeySwitchNext { get; set; } | |||
[Reactive] | |||
public bool RegisterAtStartup { get; set; } | |||
[Reactive] | |||
public string HotkeySystemProxyStatus { get; set; } | |||
[Reactive] | |||
public string HotkeyProxyModeStatus { get; set; } | |||
[Reactive] | |||
public string HotkeyAllowLanStatus { get; set; } | |||
[Reactive] | |||
public string HotkeyOpenLogsStatus { get; set; } | |||
[Reactive] | |||
public string HotkeySwitchPrevStatus { get; set; } | |||
[Reactive] | |||
public string HotkeySwitchNextStatus { get; set; } | |||
public void RecordKeyDown(int hotkeyIndex, KeyEventArgs keyEventArgs) | |||
{ | |||
var recordedKeyStringBuilder = new StringBuilder(); | |||
// record modifiers | |||
if ((Keyboard.Modifiers & ModifierKeys.Control) > 0) | |||
recordedKeyStringBuilder.Append("Ctrl+"); | |||
if ((Keyboard.Modifiers & ModifierKeys.Alt) > 0) | |||
recordedKeyStringBuilder.Append("Alt+"); | |||
if ((Keyboard.Modifiers & ModifierKeys.Shift) > 0) | |||
recordedKeyStringBuilder.Append("Shift+"); | |||
// record other keys when at least one modifier is pressed | |||
if (recordedKeyStringBuilder.Length > 0 && (keyEventArgs.Key < Key.LeftShift || keyEventArgs.Key > Key.RightAlt)) | |||
recordedKeyStringBuilder.Append(keyEventArgs.Key); | |||
switch (hotkeyIndex) | |||
{ | |||
case 0: | |||
HotkeySystemProxy = recordedKeyStringBuilder.ToString(); | |||
break; | |||
case 1: | |||
HotkeyProxyMode = recordedKeyStringBuilder.ToString(); | |||
break; | |||
case 2: | |||
HotkeyAllowLan = recordedKeyStringBuilder.ToString(); | |||
break; | |||
case 3: | |||
HotkeyOpenLogs = recordedKeyStringBuilder.ToString(); | |||
break; | |||
case 4: | |||
HotkeySwitchPrev = recordedKeyStringBuilder.ToString(); | |||
break; | |||
case 5: | |||
HotkeySwitchNext = recordedKeyStringBuilder.ToString(); | |||
break; | |||
} | |||
} | |||
public void FinishOnKeyUp(int hotkeyIndex, KeyEventArgs keyEventArgs) | |||
{ | |||
switch (hotkeyIndex) | |||
{ | |||
case 0: | |||
if (HotkeySystemProxy.EndsWith("+")) | |||
HotkeySystemProxy = ""; | |||
break; | |||
case 1: | |||
if (HotkeyProxyMode.EndsWith("+")) | |||
HotkeyProxyMode = ""; | |||
break; | |||
case 2: | |||
if (HotkeyAllowLan.EndsWith("+")) | |||
HotkeyAllowLan = ""; | |||
break; | |||
case 3: | |||
if (HotkeyOpenLogs.EndsWith("+")) | |||
HotkeyOpenLogs = ""; | |||
break; | |||
case 4: | |||
if (HotkeySwitchPrev.EndsWith("+")) | |||
HotkeySwitchPrev = ""; | |||
break; | |||
case 5: | |||
if (HotkeySwitchNext.EndsWith("+")) | |||
HotkeySwitchNext = ""; | |||
break; | |||
} | |||
} | |||
private void RegisterAllAndUpdateStatus(bool save = false) | |||
{ | |||
HotkeySystemProxyStatus = HotkeyReg.RegHotkeyFromString(HotkeySystemProxy, "SwitchSystemProxyCallback") ? "✔" : "❌"; | |||
HotkeyProxyModeStatus = HotkeyReg.RegHotkeyFromString(HotkeyProxyMode, "SwitchSystemProxyModeCallback") ? "✔" : "❌"; | |||
HotkeyAllowLanStatus = HotkeyReg.RegHotkeyFromString(HotkeyAllowLan, "SwitchAllowLanCallback") ? "✔" : "❌"; | |||
HotkeyOpenLogsStatus = HotkeyReg.RegHotkeyFromString(HotkeyOpenLogs, "ShowLogsCallback") ? "✔" : "❌"; | |||
HotkeySwitchPrevStatus = HotkeyReg.RegHotkeyFromString(HotkeySwitchPrev, "ServerMoveUpCallback") ? "✔" : "❌"; | |||
HotkeySwitchNextStatus = HotkeyReg.RegHotkeyFromString(HotkeySwitchNext, "ServerMoveDownCallback") ? "✔" : "❌"; | |||
if (HotkeySystemProxyStatus == "✔" && | |||
HotkeyProxyModeStatus == "✔" && | |||
HotkeyAllowLanStatus == "✔" && | |||
HotkeyOpenLogsStatus == "✔" && | |||
HotkeySwitchPrevStatus == "✔" && | |||
HotkeySwitchNextStatus == "✔" && save) | |||
{ | |||
_controller.SaveHotkeyConfig(GetHotkeyConfig); | |||
_menuViewController.CloseHotkeysWindow(); | |||
} | |||
} | |||
private HotkeyConfig GetHotkeyConfig => new HotkeyConfig() | |||
{ | |||
SwitchSystemProxy = HotkeySystemProxy, | |||
SwitchSystemProxyMode = HotkeyProxyMode, | |||
SwitchAllowLan = HotkeyAllowLan, | |||
ShowLogs = HotkeyOpenLogs, | |||
ServerMoveUp = HotkeySwitchPrev, | |||
ServerMoveDown = HotkeySwitchNext, | |||
RegHotkeysAtStartup = RegisterAtStartup | |||
}; | |||
} | |||
} |
@@ -1,115 +0,0 @@ | |||
<reactiveui:ReactiveUserControl | |||
x:Class="Shadowsocks.WPF.Views.HotkeysView" | |||
x:TypeArguments="vms:HotkeysViewModel" | |||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |||
xmlns:local="clr-namespace:Shadowsocks.WPF.Views" | |||
xmlns:vms="clr-namespace:Shadowsocks.WPF.ViewModels" | |||
xmlns:reactiveui="http://reactiveui.net" | |||
xmlns:lex="http://wpflocalizeextension.codeplex.com" | |||
lex:LocalizeDictionary.DesignCulture="en" | |||
lex:ResxLocalizationProvider.DefaultAssembly="Shadowsocks" | |||
lex:ResxLocalizationProvider.DefaultDictionary="Strings" | |||
mc:Ignorable="d" | |||
d:DesignHeight="240" d:DesignWidth="280"> | |||
<Grid Margin="8"> | |||
<Grid.RowDefinitions> | |||
<RowDefinition Height="Auto" /> | |||
<RowDefinition Height="Auto" /> | |||
<RowDefinition Height="Auto" /> | |||
<RowDefinition Height="Auto" /> | |||
<RowDefinition Height="Auto" /> | |||
<RowDefinition Height="Auto" /> | |||
<RowDefinition Height="Auto" /> | |||
<RowDefinition Height="*" /> | |||
</Grid.RowDefinitions> | |||
<Grid.ColumnDefinitions> | |||
<ColumnDefinition Width="Auto" /> | |||
<ColumnDefinition Width="*" /> | |||
<ColumnDefinition Width="Auto" /> | |||
</Grid.ColumnDefinitions> | |||
<TextBlock Grid.Row="0" Grid.Column="0" | |||
Margin="4" | |||
Text="{lex:Loc ToggleSystemProxy}"/> | |||
<TextBox x:Name="systemProxyTextBox" | |||
Grid.Row="0" Grid.Column="1" | |||
Margin="4" IsReadOnly="True" /> | |||
<TextBlock x:Name="systemProxyStatusTextBlock" | |||
Grid.Row="0" Grid.Column="2" | |||
Margin="4" /> | |||
<TextBlock Grid.Row="1" Grid.Column="0" | |||
Margin="4" | |||
Text="{lex:Loc ToggleProxyMode}"/> | |||
<TextBox x:Name="proxyModeTextBox" | |||
Grid.Row="1" Grid.Column="1" | |||
Margin="4" IsReadOnly="True" /> | |||
<TextBlock x:Name="proxyModeStatusTextBlock" | |||
Grid.Row="1" Grid.Column="2" | |||
Margin="4" /> | |||
<TextBlock Grid.Row="2" Grid.Column="0" | |||
Margin="4" | |||
Text="{lex:Loc AllowClientsFromLAN}"/> | |||
<TextBox x:Name="allowLanTextBox" | |||
Grid.Row="2" Grid.Column="1" | |||
Margin="4" IsReadOnly="True" /> | |||
<TextBlock x:Name="allowLanStatusTextBlock" | |||
Grid.Row="2" Grid.Column="2" | |||
Margin="4" /> | |||
<TextBlock Grid.Row="3" Grid.Column="0" | |||
Margin="4" | |||
Text="{lex:Loc OpenLogsWindow}"/> | |||
<TextBox x:Name="openLogsTextBox" | |||
Grid.Row="3" Grid.Column="1" | |||
Margin="4" IsReadOnly="True" /> | |||
<TextBlock x:Name="openLogsStatusTextBlock" | |||
Grid.Row="3" Grid.Column="2" | |||
Margin="4" /> | |||
<TextBlock Grid.Row="4" Grid.Column="0" | |||
Margin="4" | |||
Text="{lex:Loc SwitchToPreviousServer}"/> | |||
<TextBox x:Name="switchPrevTextBox" | |||
Grid.Row="4" Grid.Column="1" | |||
Margin="4" IsReadOnly="True" /> | |||
<TextBlock x:Name="switchPrevStatusTextBlock" | |||
Grid.Row="4" Grid.Column="2" | |||
Margin="4" /> | |||
<TextBlock Grid.Row="5" Grid.Column="0" | |||
Margin="4" | |||
Text="{lex:Loc SwitchToNextServer}"/> | |||
<TextBox x:Name="switchNextTextBox" | |||
Grid.Row="5" Grid.Column="1" | |||
Margin="4" IsReadOnly="True" /> | |||
<TextBlock x:Name="switchNextStatusTextBlock" | |||
Grid.Row="5" Grid.Column="2" | |||
Margin="4" /> | |||
<StackPanel Grid.Row="6" Grid.ColumnSpan="2" Orientation="Horizontal"> | |||
<CheckBox x:Name="registerAtStartupCheckBox" Margin="4" VerticalAlignment="Center"/> | |||
<TextBlock Margin="4" Text="{lex:Loc RegisterHotkeysAtStartup}"/> | |||
</StackPanel> | |||
<StackPanel Grid.Row="7" | |||
Grid.ColumnSpan="3" | |||
Orientation="Horizontal" | |||
HorizontalAlignment="Left" | |||
VerticalAlignment="Bottom"> | |||
<Button x:Name="registerAllButton" Margin="4" MinWidth="75" Content="{lex:Loc}"/> | |||
</StackPanel> | |||
<StackPanel Grid.Row="7" | |||
Grid.ColumnSpan="3" | |||
Orientation="Horizontal" | |||
HorizontalAlignment="Right" | |||
VerticalAlignment="Bottom"> | |||
<Button x:Name="saveButton" Margin="4" MinWidth="75" Content="{lex:Loc}"/> | |||
<Button x:Name="cancelButton" Margin="4" MinWidth="75" Content="{lex:Loc}"/> | |||
</StackPanel> | |||
</Grid> | |||
</reactiveui:ReactiveUserControl> |
@@ -1,169 +0,0 @@ | |||
using ReactiveUI; | |||
using Shadowsocks.WPF.ViewModels; | |||
using System; | |||
using System.Reactive.Disposables; | |||
using System.Windows; | |||
using System.Windows.Controls; | |||
using System.Windows.Data; | |||
using System.Windows.Documents; | |||
using System.Windows.Input; | |||
using System.Windows.Media; | |||
using System.Windows.Media.Imaging; | |||
using System.Windows.Navigation; | |||
namespace Shadowsocks.WPF.Views | |||
{ | |||
/// <summary> | |||
/// Interaction logic for HotkeysView.xaml | |||
/// </summary> | |||
public partial class HotkeysView : ReactiveUserControl<HotkeysViewModel> | |||
{ | |||
public HotkeysView() | |||
{ | |||
InitializeComponent(); | |||
ViewModel = new HotkeysViewModel(); | |||
this.WhenActivated(disposables => | |||
{ | |||
systemProxyTextBox | |||
.Events().KeyDown | |||
.Subscribe(keyEventArgs => ViewModel.RecordKeyDown(0, keyEventArgs)) | |||
.DisposeWith(disposables); | |||
systemProxyTextBox | |||
.Events().KeyUp | |||
.Subscribe(keyEventArgs => ViewModel.FinishOnKeyUp(0, keyEventArgs)) | |||
.DisposeWith(disposables); | |||
proxyModeTextBox | |||
.Events().KeyDown | |||
.Subscribe(keyEventArgs => ViewModel.RecordKeyDown(1, keyEventArgs)) | |||
.DisposeWith(disposables); | |||
proxyModeTextBox | |||
.Events().KeyUp | |||
.Subscribe(keyEventArgs => ViewModel.FinishOnKeyUp(1, keyEventArgs)) | |||
.DisposeWith(disposables); | |||
allowLanTextBox | |||
.Events().KeyDown | |||
.Subscribe(keyEventArgs => ViewModel.RecordKeyDown(2, keyEventArgs)) | |||
.DisposeWith(disposables); | |||
allowLanTextBox | |||
.Events().KeyUp | |||
.Subscribe(keyEventArgs => ViewModel.FinishOnKeyUp(2, keyEventArgs)) | |||
.DisposeWith(disposables); | |||
openLogsTextBox | |||
.Events().KeyDown | |||
.Subscribe(keyEventArgs => ViewModel.RecordKeyDown(3, keyEventArgs)) | |||
.DisposeWith(disposables); | |||
openLogsTextBox | |||
.Events().KeyUp | |||
.Subscribe(keyEventArgs => ViewModel.FinishOnKeyUp(3, keyEventArgs)) | |||
.DisposeWith(disposables); | |||
switchPrevTextBox | |||
.Events().KeyDown | |||
.Subscribe(keyEventArgs => ViewModel.RecordKeyDown(4, keyEventArgs)) | |||
.DisposeWith(disposables); | |||
switchPrevTextBox | |||
.Events().KeyUp | |||
.Subscribe(keyEventArgs => ViewModel.FinishOnKeyUp(4, keyEventArgs)) | |||
.DisposeWith(disposables); | |||
switchNextTextBox | |||
.Events().KeyDown | |||
.Subscribe(keyEventArgs => ViewModel.RecordKeyDown(5, keyEventArgs)) | |||
.DisposeWith(disposables); | |||
switchNextTextBox | |||
.Events().KeyUp | |||
.Subscribe(keyEventArgs => ViewModel.FinishOnKeyUp(5, keyEventArgs)) | |||
.DisposeWith(disposables); | |||
this.OneWayBind(ViewModel, | |||
viewModel => viewModel.HotkeySystemProxy, | |||
view => view.systemProxyTextBox.Text) | |||
.DisposeWith(disposables); | |||
this.OneWayBind(ViewModel, | |||
viewModel => viewModel.HotkeyProxyMode, | |||
view => view.proxyModeTextBox.Text) | |||
.DisposeWith(disposables); | |||
this.OneWayBind(ViewModel, | |||
viewModel => viewModel.HotkeyAllowLan, | |||
view => view.allowLanTextBox.Text) | |||
.DisposeWith(disposables); | |||
this.OneWayBind(ViewModel, | |||
viewModel => viewModel.HotkeyOpenLogs, | |||
view => view.openLogsTextBox.Text) | |||
.DisposeWith(disposables); | |||
this.OneWayBind(ViewModel, | |||
viewModel => viewModel.HotkeySwitchPrev, | |||
view => view.switchPrevTextBox.Text) | |||
.DisposeWith(disposables); | |||
this.OneWayBind(ViewModel, | |||
viewModel => viewModel.HotkeySwitchNext, | |||
view => view.switchNextTextBox.Text) | |||
.DisposeWith(disposables); | |||
this.Bind(ViewModel, | |||
viewModel => viewModel.RegisterAtStartup, | |||
view => view.registerAtStartupCheckBox.IsChecked) | |||
.DisposeWith(disposables); | |||
this.OneWayBind(ViewModel, | |||
viewModel => viewModel.HotkeySystemProxyStatus, | |||
view => view.systemProxyStatusTextBlock.Text) | |||
.DisposeWith(disposables); | |||
this.OneWayBind(ViewModel, | |||
viewModel => viewModel.HotkeyProxyModeStatus, | |||
view => view.proxyModeStatusTextBlock.Text) | |||
.DisposeWith(disposables); | |||
this.OneWayBind(ViewModel, | |||
viewModel => viewModel.HotkeyAllowLanStatus, | |||
view => view.allowLanStatusTextBlock.Text) | |||
.DisposeWith(disposables); | |||
this.OneWayBind(ViewModel, | |||
viewModel => viewModel.HotkeyOpenLogsStatus, | |||
view => view.openLogsStatusTextBlock.Text) | |||
.DisposeWith(disposables); | |||
this.OneWayBind(ViewModel, | |||
viewModel => viewModel.HotkeySwitchPrevStatus, | |||
view => view.switchPrevStatusTextBlock.Text) | |||
.DisposeWith(disposables); | |||
this.OneWayBind(ViewModel, | |||
viewModel => viewModel.HotkeySwitchNextStatus, | |||
view => view.switchNextStatusTextBlock.Text) | |||
.DisposeWith(disposables); | |||
this.BindCommand(ViewModel, | |||
viewModel => viewModel.RegisterAll, | |||
view => view.registerAllButton) | |||
.DisposeWith(disposables); | |||
this.BindCommand(ViewModel, | |||
viewModel => viewModel.Save, | |||
view => view.saveButton) | |||
.DisposeWith(disposables); | |||
this.BindCommand(ViewModel, | |||
viewModel => viewModel.Cancel, | |||
view => view.cancelButton) | |||
.DisposeWith(disposables); | |||
}); | |||
} | |||
} | |||
} |
@@ -2,6 +2,7 @@ | |||
<PropertyGroup> | |||
<TargetFramework>netcoreapp3.1</TargetFramework> | |||
<Nullable>enable</Nullable> | |||
</PropertyGroup> | |||
</Project> |
@@ -85,6 +85,15 @@ cache: | |||
# "project" is relative to the original build directory and not influenced by directory changes in "before_build". | |||
build: | |||
# parallel: true # enable MSBuild parallel builds | |||
# project: MyTestAzureCS.sln # path to Visual Studio solution or project | |||
# publish_wap: true # package Web Application Projects (WAP) for Web Deploy | |||
# publish_wap_xcopy: true # package Web Application Projects (WAP) for XCopy deployment | |||
# publish_wap_beanstalk: true # Package Web Applications for AWS Elastic Beanstalk deployment | |||
# publish_wap_octopus: true # Package Web Applications for Octopus deployment | |||
# publish_azure_webjob: true # Package Azure WebJobs for Zip Push deployment | |||
# publish_azure: true # package Azure Cloud Service projects and push to artifacts | |||
# publish_aspnet_core: true # Package ASP.NET Core projects | |||
# publish_core_console: true # Package .NET Core console projects | |||
# publish_nuget: true # package projects with .nuspec files and push to artifacts | |||
# publish_nuget_symbols: true # generate and publish NuGet symbol packages | |||
# include_nuget_references: true # add -IncludeReferencedProjects option while packaging NuGet artifacts | |||
@@ -121,22 +130,24 @@ after_build: | |||
$WorkingFolder = "$env:APPVEYOR_BUILD_FOLDER\working" | |||
New-Item $WorkingFolder -ItemType Directory -Force | |||
$HashFile = "all.hash" | |||
$TargetProjectFile = "$env:APPVEYOR_BUILD_FOLDER\Shadowsocks.WPF\Shadowsocks.WPF.csproj" | |||
# Publish and deploy | |||
# Normal package | |||
dotnet publish -c $env:CONFIGURATION $env:APPVEYOR_BUILD_FOLDER\shadowsocks-csharp\shadowsocks-csharp.csproj | |||
dotnet publish -c $env:CONFIGURATION $TargetProjectFile | |||
# Package into a self-contained single-file executable | |||
dotnet publish -r win-x64 -c $env:CONFIGURATION -p:PublishSingleFile=true -p:PublishTrimmed=true $env:APPVEYOR_BUILD_FOLDER\shadowsocks-csharp\shadowsocks-csharp.csproj | |||
dotnet publish -r win-x86 -c $env:CONFIGURATION -p:PublishSingleFile=true -p:PublishTrimmed=true $env:APPVEYOR_BUILD_FOLDER\shadowsocks-csharp\shadowsocks-csharp.csproj | |||
dotnet publish -r win-x64 -c $env:CONFIGURATION -p:PublishSingleFile=true -p:PublishTrimmed=true $TargetProjectFile | |||
dotnet publish -r win-x86 -c $env:CONFIGURATION -p:PublishSingleFile=true -p:PublishTrimmed=true $TargetProjectFile | |||
$ZipDev = "$WorkingFolder\shadowsocks-windows-$env:APPVEYOR_BUILD_VERSION-dev.zip" | |||
$ZipMinimal = "$WorkingFolder\shadowsocks-windows-$env:APPVEYOR_BUILD_VERSION-minimal.zip" | |||
$ZipSingleExeX64 = "$WorkingFolder\shadowsocks-windows-$env:APPVEYOR_BUILD_VERSION-portable-x64.zip" | |||
$ZipSingleExeX86 = "$WorkingFolder\shadowsocks-windows-$env:APPVEYOR_BUILD_VERSION-portable-x86.zip" | |||
7z a $ZipDev "$env:APPVEYOR_BUILD_FOLDER\shadowsocks-csharp\bin\$env:CONFIGURATION\netcoreapp3.1\*" | |||
7z a $ZipMinimal "$env:APPVEYOR_BUILD_FOLDER\shadowsocks-csharp\bin\Any CPU\$env:CONFIGURATION\netcoreapp3.1\publish\*" | |||
7z a $ZipSingleExeX64 "$env:APPVEYOR_BUILD_FOLDER\shadowsocks-csharp\bin\Any CPU\$env:CONFIGURATION\netcoreapp3.1\win-x64\publish\Shadowsocks.exe" | |||
7z a $ZipSingleExeX86 "$env:APPVEYOR_BUILD_FOLDER\shadowsocks-csharp\bin\Any CPU\$env:CONFIGURATION\netcoreapp3.1\win-x86\publish\Shadowsocks.exe" | |||
7z a $ZipDev "$env:APPVEYOR_BUILD_FOLDER\Shadowsocks.WPF\bin\$env:CONFIGURATION\netcoreapp3.1\*" | |||
7z a $ZipMinimal "$env:APPVEYOR_BUILD_FOLDER\Shadowsocks.WPF\bin\Any CPU\$env:CONFIGURATION\netcoreapp3.1\publish\*" | |||
7z a $ZipSingleExeX64 "$env:APPVEYOR_BUILD_FOLDER\Shadowsocks.WPF\bin\Any CPU\$env:CONFIGURATION\netcoreapp3.1\win-x64\publish\Shadowsocks.exe" | |||
7z a $ZipSingleExeX86 "$env:APPVEYOR_BUILD_FOLDER\Shadowsocks.WPF\bin\Any CPU\$env:CONFIGURATION\netcoreapp3.1\win-x86\publish\Shadowsocks.exe" | |||
Calculate-Hash -file $ZipDev | Out-File -FilePath $HashFile -Append | |||
Calculate-Hash -file $ZipMinimal | Out-File -FilePath $HashFile -Append | |||
Calculate-Hash -file $ZipSingleExeX64 | Out-File -FilePath $HashFile -Append | |||
@@ -1,20 +1,20 @@ | |||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> | |||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> | |||
<PropertyGroup> | |||
<OutputType>WinExe</OutputType> | |||
<TargetFramework>netcoreapp3.1</TargetFramework> | |||
<RootNamespace>Shadowsocks</RootNamespace> | |||
<UseWPF>true</UseWPF> | |||
<UseWindowsForms>true</UseWindowsForms> | |||
<Authors>clowwindy & community 2020</Authors> | |||
<PackageId>Shadowsocks</PackageId> | |||
<Product>Shadowsocks</Product> | |||
<PackageId>Shadowsocks.Legacy</PackageId> | |||
<Product>Shadowsocks Legacy Project</Product> | |||
<Version>4.3.0.0</Version> | |||
<AssemblyName>Shadowsocks</AssemblyName> | |||
<ApplicationIcon>shadowsocks.ico</ApplicationIcon> | |||
<StartupObject>Shadowsocks.Program</StartupObject> | |||
<Nullable>disable</Nullable> | |||
<ApplicationManifest>app.manifest</ApplicationManifest> | |||
<RootNamespace>Shadowsocks.Legacy</RootNamespace> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
@@ -55,10 +55,6 @@ | |||
<PackageReference Include="ZXing.Net" Version="0.16.6" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\Shadowsocks.WPF\Shadowsocks.WPF.csproj" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<Resource Include="Data\i18n.csv" /> | |||
</ItemGroup> | |||