Browse Source

🔩 Enable nullable, remove hotkey and clean up some stuff

pull/3073/head
database64128 4 years ago
parent
commit
f00794678c
No known key found for this signature in database GPG Key ID: 1CA27546BEDB8B01
17 changed files with 337 additions and 1023 deletions
  1. +3
    -3
      Shadowsocks.PAC/GeositeUpdater.cs
  2. +4
    -3
      Shadowsocks.PAC/PACServer.cs
  3. +1
    -0
      Shadowsocks.PAC/Shadowsocks.PAC.csproj
  4. +0
    -91
      Shadowsocks.WPF/Behaviors/HotkeyReg.cs
  5. +0
    -114
      Shadowsocks.WPF/Behaviors/Hotkeys/HotkeyCallbacks.cs
  6. +0
    -174
      Shadowsocks.WPF/Behaviors/Hotkeys/Hotkeys.cs
  7. +0
    -143
      Shadowsocks.WPF/Behaviors/LoggerExtension.cs
  8. +1
    -1
      Shadowsocks.WPF/Properties/PublishProfiles/FolderProfile.pubxml
  9. +105
    -0
      Shadowsocks.WPF/Properties/Resources.Designer.cs
  10. +130
    -0
      Shadowsocks.WPF/Properties/Resources.resx
  11. +70
    -6
      Shadowsocks.WPF/Shadowsocks.WPF.csproj
  12. +0
    -189
      Shadowsocks.WPF/ViewModels/HotkeysViewModel.cs
  13. +0
    -115
      Shadowsocks.WPF/Views/HotkeysView.xaml
  14. +0
    -169
      Shadowsocks.WPF/Views/HotkeysView.xaml.cs
  15. +1
    -0
      Shadowsocks/Shadowsocks.csproj
  16. +18
    -7
      appveyor.yml
  17. +4
    -8
      shadowsocks-csharp/shadowsocks-csharp.csproj

+ 3
- 3
Shadowsocks.PAC/GeositeUpdater.cs View File

@@ -23,9 +23,9 @@ namespace Shadowsocks.PAC


public class GeositeUpdater : IEnableLogger 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; private readonly string DATABASE_PATH;


@@ -230,7 +230,7 @@ var __RULES__ = {JsonSerializer.Serialize(ruleLines, jsonSerializerOptions)};
List<string> valid_lines = new List<string>(); List<string> valid_lines = new List<string>();
using (var stringReader = new StringReader(content)) 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("[")) if (string.IsNullOrWhiteSpace(line) || line.StartsWith("!") || line.StartsWith("["))
continue; continue;


+ 4
- 3
Shadowsocks.PAC/PACServer.cs View File

@@ -189,13 +189,14 @@ Connection: Close


private void SendCallback(IAsyncResult ar) private void SendCallback(IAsyncResult ar)
{ {
Socket conn = (Socket)ar.AsyncState;
Socket? conn = ar.AsyncState as Socket;
try try
{ {
conn.Shutdown(SocketShutdown.Send);
conn?.Shutdown(SocketShutdown.Send);
} }
catch catch
{ }
{
}
} }


private string GetPACAddress(IPEndPoint localEndPoint, bool useSocks) => $"{(useSocks ? "SOCKS5" : "PROXY")} {localEndPoint};"; private string GetPACAddress(IPEndPoint localEndPoint, bool useSocks) => $"{(useSocks ? "SOCKS5" : "PROXY")} {localEndPoint};";


+ 1
- 0
Shadowsocks.PAC/Shadowsocks.PAC.csproj View File

@@ -2,6 +2,7 @@


<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>


<ItemGroup> <ItemGroup>


+ 0
- 91
Shadowsocks.WPF/Behaviors/HotkeyReg.cs View File

@@ -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
}
}
}

+ 0
- 114
Shadowsocks.WPF/Behaviors/Hotkeys/HotkeyCallbacks.cs View File

@@ -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
}
}

+ 0
- 174
Shadowsocks.WPF/Behaviors/Hotkeys/Hotkeys.cs View File

@@ -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);
}
}
}

+ 0
- 143
Shadowsocks.WPF/Behaviors/LoggerExtension.cs View File

@@ -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);
}
}
}
}

+ 1
- 1
Shadowsocks.WPF/Properties/PublishProfiles/FolderProfile.pubxml View File

@@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
--> -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration>Debug</Configuration>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform> <Platform>Any CPU</Platform>
<PublishDir>bin\Release\netcoreapp3.1\publish\</PublishDir> <PublishDir>bin\Release\netcoreapp3.1\publish\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol> <PublishProtocol>FileSystem</PublishProtocol>


+ 105
- 0
Shadowsocks.WPF/Properties/Resources.Designer.cs View File

@@ -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 &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
///&lt;!-- Warning: Configuration may reset after shadowsocks upgrade. --&gt;
///&lt;!-- If you messed it up, delete this file and Shadowsocks will create a new one. --&gt;
///&lt;nlog xmlns=&quot;http://www.nlog-project.org/schemas/NLog.xsd&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&gt;
/// &lt;targets&gt;
/// &lt;!-- This line is managed by Shadowsocks. Do not modify it unless you know what you are doing.--&gt;
/// &lt;target name=&quot;file&quot; xsi:type=&quot;File&quot; fileName=&quot;ss_win_temp\shadowsocks [rest of string was truncated]&quot;;.
/// </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));
}
}
}
}

+ 130
- 0
Shadowsocks.WPF/Properties/Resources.resx View File

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

+ 70
- 6
Shadowsocks.WPF/Shadowsocks.WPF.csproj View File

@@ -11,15 +11,46 @@
<Version>1.0.0</Version> <Version>1.0.0</Version>
<ApplicationIcon>Assets\shadowsocks.ico</ApplicationIcon> <ApplicationIcon>Assets\shadowsocks.ico</ApplicationIcon>
<NoWin32Manifest>true</NoWin32Manifest> <NoWin32Manifest>true</NoWin32Manifest>
<Nullable>enable</Nullable>
</PropertyGroup> </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> <ItemGroup>
<PackageReference Include="MaterialDesignThemes" Version="3.2.0" /> <PackageReference Include="MaterialDesignThemes" Version="3.2.0" />
<PackageReference Include="MdXaml" Version="1.6.0" />
<PackageReference Include="OxyPlot.Wpf" Version="2.0.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.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="System.CommandLine" Version="2.0.0-beta1.20371.2" />
<PackageReference Include="WPFLocalizeExtension" Version="3.8.0" /> <PackageReference Include="WPFLocalizeExtension" Version="3.8.0" />
<PackageReference Include="ZXing.Net" Version="0.16.6" /> <PackageReference Include="ZXing.Net" Version="0.16.6" />
@@ -31,6 +62,11 @@
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DependentUpon>Strings.resx</DependentUpon> <DependentUpon>Strings.resx</DependentUpon>
</Compile> </Compile>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup> </ItemGroup>


<ItemGroup> <ItemGroup>
@@ -38,15 +74,43 @@
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.Designer.cs</LastGenOutput> <LastGenOutput>Strings.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup> </ItemGroup>


<ItemGroup> <ItemGroup>
<Folder Include="Resources\" />
<ProjectReference Include="..\Shadowsocks.Net\Shadowsocks.Net.csproj" />
<ProjectReference Include="..\Shadowsocks\Shadowsocks.csproj" />
</ItemGroup> </ItemGroup>


<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> </ItemGroup>


</Project> </Project>

+ 0
- 189
Shadowsocks.WPF/ViewModels/HotkeysViewModel.cs View File

@@ -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
};
}
}

+ 0
- 115
Shadowsocks.WPF/Views/HotkeysView.xaml View File

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

+ 0
- 169
Shadowsocks.WPF/Views/HotkeysView.xaml.cs View File

@@ -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);
});
}
}
}

+ 1
- 0
Shadowsocks/Shadowsocks.csproj View File

@@ -2,6 +2,7 @@


<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>


</Project> </Project>

+ 18
- 7
appveyor.yml View File

@@ -85,6 +85,15 @@ cache:
# "project" is relative to the original build directory and not influenced by directory changes in "before_build". # "project" is relative to the original build directory and not influenced by directory changes in "before_build".
build: build:
# parallel: true # enable MSBuild parallel builds # 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: true # package projects with .nuspec files and push to artifacts
# publish_nuget_symbols: true # generate and publish NuGet symbol packages # publish_nuget_symbols: true # generate and publish NuGet symbol packages
# include_nuget_references: true # add -IncludeReferencedProjects option while packaging NuGet artifacts # include_nuget_references: true # add -IncludeReferencedProjects option while packaging NuGet artifacts
@@ -121,22 +130,24 @@ after_build:
$WorkingFolder = "$env:APPVEYOR_BUILD_FOLDER\working" $WorkingFolder = "$env:APPVEYOR_BUILD_FOLDER\working"
New-Item $WorkingFolder -ItemType Directory -Force New-Item $WorkingFolder -ItemType Directory -Force
$HashFile = "all.hash" $HashFile = "all.hash"
$TargetProjectFile = "$env:APPVEYOR_BUILD_FOLDER\Shadowsocks.WPF\Shadowsocks.WPF.csproj"
# Publish and deploy # Publish and deploy
# Normal package # 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 # 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" $ZipDev = "$WorkingFolder\shadowsocks-windows-$env:APPVEYOR_BUILD_VERSION-dev.zip"
$ZipMinimal = "$WorkingFolder\shadowsocks-windows-$env:APPVEYOR_BUILD_VERSION-minimal.zip" $ZipMinimal = "$WorkingFolder\shadowsocks-windows-$env:APPVEYOR_BUILD_VERSION-minimal.zip"
$ZipSingleExeX64 = "$WorkingFolder\shadowsocks-windows-$env:APPVEYOR_BUILD_VERSION-portable-x64.zip" $ZipSingleExeX64 = "$WorkingFolder\shadowsocks-windows-$env:APPVEYOR_BUILD_VERSION-portable-x64.zip"
$ZipSingleExeX86 = "$WorkingFolder\shadowsocks-windows-$env:APPVEYOR_BUILD_VERSION-portable-x86.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 $ZipDev | Out-File -FilePath $HashFile -Append
Calculate-Hash -file $ZipMinimal | Out-File -FilePath $HashFile -Append Calculate-Hash -file $ZipMinimal | Out-File -FilePath $HashFile -Append
Calculate-Hash -file $ZipSingleExeX64 | Out-File -FilePath $HashFile -Append Calculate-Hash -file $ZipSingleExeX64 | Out-File -FilePath $HashFile -Append


+ 4
- 8
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -1,20 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>Shadowsocks</RootNamespace>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<Authors>clowwindy &amp; community 2020</Authors> <Authors>clowwindy &amp; community 2020</Authors>
<PackageId>Shadowsocks</PackageId>
<Product>Shadowsocks</Product>
<PackageId>Shadowsocks.Legacy</PackageId>
<Product>Shadowsocks Legacy Project</Product>
<Version>4.3.0.0</Version> <Version>4.3.0.0</Version>
<AssemblyName>Shadowsocks</AssemblyName> <AssemblyName>Shadowsocks</AssemblyName>
<ApplicationIcon>shadowsocks.ico</ApplicationIcon> <ApplicationIcon>shadowsocks.ico</ApplicationIcon>
<StartupObject>Shadowsocks.Program</StartupObject> <StartupObject>Shadowsocks.Program</StartupObject>
<Nullable>disable</Nullable> <Nullable>disable</Nullable>
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>app.manifest</ApplicationManifest>
<RootNamespace>Shadowsocks.Legacy</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -55,10 +55,6 @@
<PackageReference Include="ZXing.Net" Version="0.16.6" /> <PackageReference Include="ZXing.Net" Version="0.16.6" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Shadowsocks.WPF\Shadowsocks.WPF.csproj" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Resource Include="Data\i18n.csv" /> <Resource Include="Data\i18n.csv" />
</ItemGroup> </ItemGroup>


Loading…
Cancel
Save