diff --git a/.gitignore b/.gitignore index 42698ddd..4f3e075c 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ /v2rayN/v2rayUpgrade/bin/Release /v2rayN/v2rayUpgrade/obj/ *.user +/.vs/v2rayN diff --git a/v2rayN/v2rayN/Base/SqliteHelper.cs b/v2rayN/v2rayN/Base/SqliteHelper.cs index 60c60811..c4250afa 100644 --- a/v2rayN/v2rayN/Base/SqliteHelper.cs +++ b/v2rayN/v2rayN/Base/SqliteHelper.cs @@ -25,11 +25,18 @@ namespace v2rayN.Base return _db.CreateTable(); } - public int Add(object model) + public int Insert(object model) { return _db.Insert(model); } - public async Task AddAsync(object model) + public int InsertAll(IEnumerable models) + { + lock (objLock) + { + return _db.InsertAll(models); + } + } + public async Task InsertAsync(object model) { return await _dbAsync.InsertAsync(model); } diff --git a/v2rayN/v2rayN/Global.cs b/v2rayN/v2rayN/Global.cs index 93f07339..1edbe712 100644 --- a/v2rayN/v2rayN/Global.cs +++ b/v2rayN/v2rayN/Global.cs @@ -43,7 +43,7 @@ public const string directTag = "direct"; public const string blockTag = "block"; public const string StreamSecurity = "tls"; - public const string StreamSecurityX = "xtls"; + public const string StreamSecurityReality = "reality"; public const string InboundSocks = "socks"; public const string InboundHttp = "http"; public const string InboundSocks2 = "socks2"; @@ -92,7 +92,7 @@ public static readonly List ssSecuritys = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" }; public static readonly List ssSecuritysInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" }; public static readonly List ssSecuritysInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" }; - public static readonly List xtlsFlows = new() { "", "xtls-rprx-origin", "xtls-rprx-origin-udp443", "xtls-rprx-direct", "xtls-rprx-direct-udp443", "xtls-rprx-vision", "xtls-rprx-vision-udp443" }; + public static readonly List flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" }; public static readonly List networks = new() { "tcp", "kcp", "ws", "h2", "quic", "grpc" }; public static readonly List kcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" }; public static readonly List coreTypes = new() { "v2fly", "SagerNet", "Xray", "v2fly_v5" }; diff --git a/v2rayN/v2rayN/Handler/ConfigHandler.cs b/v2rayN/v2rayN/Handler/ConfigHandler.cs index 55ffed3f..1e15824a 100644 --- a/v2rayN/v2rayN/Handler/ConfigHandler.cs +++ b/v2rayN/v2rayN/Handler/ConfigHandler.cs @@ -352,7 +352,7 @@ namespace v2rayN.Handler /// /// /// - public static int AddServer(ref Config config, ProfileItem profileItem) + public static int AddServer(ref Config config, ProfileItem profileItem, bool toFile = true) { profileItem.configType = EConfigType.VMess; @@ -370,7 +370,7 @@ namespace v2rayN.Handler return -1; } - AddServerCommon(ref config, profileItem); + AddServerCommon(ref config, profileItem, toFile); return 0; } @@ -383,11 +383,15 @@ namespace v2rayN.Handler /// public static int RemoveServer(Config config, List indexs) { + var subid = "TempRemoveSubId"; foreach (var item in indexs) { - RemoveProfileItem(config, item.indexId); + item.subid = subid; } + SqliteHelper.Instance.UpdateAll(indexs); + RemoveServerViaSubid(ref config, subid, false); + return 0; } @@ -399,8 +403,14 @@ namespace v2rayN.Handler /// public static int CopyServer(ref Config config, List indexs) { - foreach (var item in indexs) + foreach (var it in indexs) { + var item = LazyConfig.Instance.GetProfileItem(it.indexId); + if (item is null) + { + continue; + } + ProfileItem profileItem = Utils.DeepCopy(item); profileItem.indexId = string.Empty; profileItem.remarks = $"{item.remarks}-clone"; @@ -414,7 +424,7 @@ namespace v2rayN.Handler } else { - AddServerCommon(ref config, profileItem); + AddServerCommon(ref config, profileItem, true); } } @@ -447,8 +457,7 @@ namespace v2rayN.Handler { return 0; } - var allItems = LazyConfig.Instance.ProfileItemIndexs(""); - if (allItems.Where(t => t == config.indexId).Any()) + if (SqliteHelper.Instance.Table().Where(t => t.indexId == config.indexId).Any()) { return 0; } @@ -456,11 +465,7 @@ namespace v2rayN.Handler { return SetDefaultServerIndex(ref config, lstProfile[0].indexId); } - if (allItems.Count > 0) - { - return SetDefaultServerIndex(ref config, allItems.FirstOrDefault()); - } - return -1; + return SetDefaultServerIndex(ref config, SqliteHelper.Instance.Table().Select(t => t.indexId).FirstOrDefault()); } public static ProfileItem? GetDefaultServer(ref Config config) { @@ -588,7 +593,7 @@ namespace v2rayN.Handler } - AddServerCommon(ref config, profileItem); + AddServerCommon(ref config, profileItem, true); return 0; @@ -620,7 +625,7 @@ namespace v2rayN.Handler /// /// /// - public static int AddShadowsocksServer(ref Config config, ProfileItem profileItem) + public static int AddShadowsocksServer(ref Config config, ProfileItem profileItem, bool toFile = true) { profileItem.configType = EConfigType.Shadowsocks; @@ -633,7 +638,7 @@ namespace v2rayN.Handler return -1; } - AddServerCommon(ref config, profileItem); + AddServerCommon(ref config, profileItem, toFile); return 0; } @@ -644,13 +649,13 @@ namespace v2rayN.Handler /// /// /// - public static int AddSocksServer(ref Config config, ProfileItem profileItem) + public static int AddSocksServer(ref Config config, ProfileItem profileItem, bool toFile = true) { profileItem.configType = EConfigType.Socks; profileItem.address = profileItem.address.TrimEx(); - AddServerCommon(ref config, profileItem); + AddServerCommon(ref config, profileItem, toFile); return 0; } @@ -661,7 +666,7 @@ namespace v2rayN.Handler /// /// /// - public static int AddTrojanServer(ref Config config, ProfileItem profileItem) + public static int AddTrojanServer(ref Config config, ProfileItem profileItem, bool toFile = true) { profileItem.configType = EConfigType.Trojan; @@ -671,12 +676,8 @@ namespace v2rayN.Handler { profileItem.streamSecurity = Global.StreamSecurity; } - if (Utils.IsNullOrEmpty(profileItem.allowInsecure)) - { - profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower(); - } - AddServerCommon(ref config, profileItem); + AddServerCommon(ref config, profileItem, toFile); return 0; } @@ -781,7 +782,7 @@ namespace v2rayN.Handler /// /// /// - public static int AddVlessServer(ref Config config, ProfileItem profileItem) + public static int AddVlessServer(ref Config config, ProfileItem profileItem, bool toFile = true) { profileItem.configType = EConfigType.VLESS; @@ -794,7 +795,7 @@ namespace v2rayN.Handler profileItem.path = profileItem.path.TrimEx(); profileItem.streamSecurity = profileItem.streamSecurity.TrimEx(); - AddServerCommon(ref config, profileItem); + AddServerCommon(ref config, profileItem, toFile); return 0; } @@ -804,33 +805,42 @@ namespace v2rayN.Handler List source = lstProfile; bool keepOlder = config.guiItem.keepOlderDedupl; - List list = new(); + List lstKeep = new(); + List lstRemove = new(); if (!keepOlder) source.Reverse(); // Remove the early items first foreach (ProfileItem item in source) { - if (!list.Exists(i => CompareProfileItem(i, item, false))) + if (!lstKeep.Exists(i => CompareProfileItem(i, item, false))) { - list.Add(item); + lstKeep.Add(item); } else { - RemoveProfileItem(config, item.indexId); + lstRemove.Add(item); } } - //if (!keepOlder) list.Reverse(); - //config.vmess = list; + RemoveServer(config, lstRemove); - return list.Count; + return lstKeep.Count; } - public static int AddServerCommon(ref Config config, ProfileItem profileItem) + public static int AddServerCommon(ref Config config, ProfileItem profileItem, bool toFile = true) { profileItem.configVersion = 2; - if (Utils.IsNullOrEmpty(profileItem.allowInsecure)) + + if (!Utils.IsNullOrEmpty(profileItem.streamSecurity)) { - profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower(); + if (Utils.IsNullOrEmpty(profileItem.allowInsecure)) + { + profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower(); + } + if (Utils.IsNullOrEmpty(profileItem.fingerprint)) + { + profileItem.fingerprint = config.coreBasicItem.defFingerprint; + } } + if (!Utils.IsNullOrEmpty(profileItem.network) && !Global.networks.Contains(profileItem.network)) { profileItem.network = Global.DefaultNetwork; @@ -842,18 +852,12 @@ namespace v2rayN.Handler var maxSort = ProfileExHandler.Instance.GetMaxSort(); ProfileExHandler.Instance.SetSort(profileItem.indexId, maxSort + 1); } - else if (profileItem.indexId == config.indexId) - { - } - if (SqliteHelper.Instance.Replace(profileItem) > 0) + if (toFile) { - return 0; - } - else - { - return -1; + SqliteHelper.Instance.Replace(profileItem); } + return 0; } private static bool CompareProfileItem(ProfileItem o, ProfileItem n, bool remarks) @@ -930,11 +934,7 @@ namespace v2rayN.Handler } int countServers = 0; - //var maxSort = 0; - //if (SqliteHelper.Instance.Table().Count() > 0) - //{ - // maxSort = SqliteHelper.Instance.Table().Max(t => t.sort); - //} + List lstAdd = new(); string[] arrData = clipboardData.Split(Environment.NewLine.ToCharArray()); foreach (string str in arrData) { @@ -972,45 +972,47 @@ namespace v2rayN.Handler } profileItem.subid = subid; profileItem.isSub = isSub; - //profileItem.sort = maxSort + countServers + 1; if (profileItem.configType == EConfigType.VMess) { - if (AddServer(ref config, profileItem) == 0) + if (AddServer(ref config, profileItem, false) == 0) { countServers++; } } else if (profileItem.configType == EConfigType.Shadowsocks) { - if (AddShadowsocksServer(ref config, profileItem) == 0) + if (AddShadowsocksServer(ref config, profileItem, false) == 0) { countServers++; } } else if (profileItem.configType == EConfigType.Socks) { - if (AddSocksServer(ref config, profileItem) == 0) + if (AddSocksServer(ref config, profileItem, false) == 0) { countServers++; } } else if (profileItem.configType == EConfigType.Trojan) { - if (AddTrojanServer(ref config, profileItem) == 0) + if (AddTrojanServer(ref config, profileItem, false) == 0) { countServers++; } } else if (profileItem.configType == EConfigType.VLESS) { - if (AddVlessServer(ref config, profileItem) == 0) + if (AddVlessServer(ref config, profileItem, false) == 0) { countServers++; } } + lstAdd.Add(profileItem); } + SqliteHelper.Instance.InsertAll(lstAdd); + ToJsonFile(config); return countServers; } @@ -1260,6 +1262,7 @@ namespace v2rayN.Handler { return -1; } + var customProfile = SqliteHelper.Instance.Table().Where(t => t.subid == subid && t.configType == EConfigType.Custom).ToList(); if (isSub) { SqliteHelper.Instance.Execute($"delete from ProfileItem where isSub = 1 and subid = '{subid}'"); @@ -1268,6 +1271,10 @@ namespace v2rayN.Handler { SqliteHelper.Instance.Execute($"delete from ProfileItem where subid = '{subid}'"); } + foreach (var item in customProfile) + { + File.Delete(Utils.GetConfigPath(item.address)); + } return 0; } diff --git a/v2rayN/v2rayN/Handler/CoreConfigHandler.cs b/v2rayN/v2rayN/Handler/CoreConfigHandler.cs index 4b5bc51e..c710fb3f 100644 --- a/v2rayN/v2rayN/Handler/CoreConfigHandler.cs +++ b/v2rayN/v2rayN/Handler/CoreConfigHandler.cs @@ -456,17 +456,9 @@ namespace v2rayN.Handler boundStreamSettings(node, "out", outbound.streamSettings); - //if xtls - if (node.streamSecurity == Global.StreamSecurityX) + if (node.streamSecurity == Global.StreamSecurityReality) { - if (Utils.IsNullOrEmpty(node.flow)) - { - usersItem.flow = Global.xtlsFlows[1]; - } - else - { - usersItem.flow = node.flow.Replace("splice", "direct"); - } + usersItem.flow = node.flow; outbound.mux.enabled = false; outbound.mux.concurrency = -1; @@ -505,22 +497,6 @@ namespace v2rayN.Handler serversItem.ota = false; serversItem.level = 1; - //if xtls - if (node.streamSecurity == Global.StreamSecurityX) - { - if (Utils.IsNullOrEmpty(node.flow)) - { - serversItem.flow = Global.xtlsFlows[1]; - } - else - { - serversItem.flow = node.flow.Replace("splice", "direct"); - } - - outbound.mux.enabled = false; - outbound.mux.concurrency = -1; - } - outbound.mux.enabled = false; outbound.mux.concurrency = -1; @@ -581,26 +557,21 @@ namespace v2rayN.Handler streamSettings.tlsSettings = tlsSettings; } - //if xtls - if (node.streamSecurity == Global.StreamSecurityX) + //if Reality + if (node.streamSecurity == Global.StreamSecurityReality) { streamSettings.security = node.streamSecurity; - TlsSettings xtlsSettings = new() + TlsSettings realitySettings = new() { - allowInsecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure), - alpn = node.GetAlpn(), - fingerprint = node.fingerprint.IsNullOrEmpty() ? config.coreBasicItem.defFingerprint : node.fingerprint + fingerprint = node.fingerprint.IsNullOrEmpty() ? config.coreBasicItem.defFingerprint : node.fingerprint, + serverName = sni, + publicKey = node.publicKey, + shortId = node.shortId, + spiderX = node.spiderX, }; - if (!string.IsNullOrWhiteSpace(sni)) - { - xtlsSettings.serverName = sni; - } - else if (!string.IsNullOrWhiteSpace(host)) - { - xtlsSettings.serverName = Utils.String2List(host)[0]; - } - streamSettings.xtlsSettings = xtlsSettings; + + streamSettings.realitySettings = realitySettings; } //streamSettings @@ -660,13 +631,6 @@ namespace v2rayN.Handler } streamSettings.wsSettings = wsSettings; - //TlsSettings tlsSettings = new TlsSettings(); - //tlsSettings.allowInsecure = config.allowInsecure(); - //if (!string.IsNullOrWhiteSpace(host)) - //{ - // tlsSettings.serverName = host; - //} - //streamSettings.tlsSettings = tlsSettings; break; //h2 case "h2": @@ -680,9 +644,6 @@ namespace v2rayN.Handler streamSettings.httpSettings = httpSettings; - //TlsSettings tlsSettings2 = new TlsSettings(); - //tlsSettings2.allowInsecure = config.allowInsecure(); - //streamSettings.tlsSettings = tlsSettings2; break; //quic case "quic": @@ -718,7 +679,6 @@ namespace v2rayN.Handler permit_without_stream = config.grpcItem.permit_without_stream, initial_windows_size = config.grpcItem.initial_windows_size, }; - streamSettings.grpcSettings = grpcSettings; break; default: diff --git a/v2rayN/v2rayN/Handler/HotkeyHandler.cs b/v2rayN/v2rayN/Handler/HotkeyHandler.cs new file mode 100644 index 00000000..a4724571 --- /dev/null +++ b/v2rayN/v2rayN/Handler/HotkeyHandler.cs @@ -0,0 +1,172 @@ +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows; +using System.Windows.Input; +using System.Windows.Interop; +using v2rayN.Mode; +using v2rayN.Resx; + +namespace v2rayN.Handler +{ + public sealed class HotkeyHandler + { + private static readonly Lazy _instance = new(() => new()); + public static HotkeyHandler Instance = _instance.Value; + + private const int WmHotkey = 0x0312; + private Config _config + { + get => LazyConfig.Instance.GetConfig(); + } + private Dictionary> _hotkeyTriggerDic; + + public bool IsPause { get; set; } = false; + public event Action? UpdateViewEvent; + public event Action? HotkeyTriggerEvent; + public HotkeyHandler() + { + _hotkeyTriggerDic = new(); + ComponentDispatcher.ThreadPreprocessMessage += OnThreadPreProcessMessage; + Init(); + } + + private void Init() + { + _hotkeyTriggerDic.Clear(); + if (_config.globalHotkeys == null) return; + foreach (var item in _config.globalHotkeys) + { + if (item.KeyCode != null && item.KeyCode != Key.None) + { + int key = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode); + KeyModifiers modifiers = KeyModifiers.None; + if (item.Control) modifiers |= KeyModifiers.Ctrl; + if (item.Shift) modifiers |= KeyModifiers.Shift; + if (item.Alt) modifiers |= KeyModifiers.Alt; + key = (key << 16) | (int)modifiers; + if (!_hotkeyTriggerDic.ContainsKey(key)) + { + _hotkeyTriggerDic.Add(key, new() { item.eGlobalHotkey }); + } + else + { + if (!_hotkeyTriggerDic[key].Contains(item.eGlobalHotkey)) + _hotkeyTriggerDic[key].Add(item.eGlobalHotkey); + } + } + } + } + public void Load() + { + foreach (var _hotkeyCode in _hotkeyTriggerDic.Keys) + { + var hotkeyInfo = GetHotkeyInfo(_hotkeyCode); + bool isSuccess = false; + string msg; + + Application.Current.Dispatcher.Invoke(() => + { + isSuccess = RegisterHotKey(IntPtr.Zero, _hotkeyCode, hotkeyInfo.fsModifiers, hotkeyInfo.vKey); + }); + foreach (var name in hotkeyInfo.Names) + { + if (isSuccess) + { + msg = string.Format(ResUI.RegisterGlobalHotkeySuccessfully, $"{name}({hotkeyInfo.hotkeyStr})"); + } + else + { + var errInfo = new Win32Exception(Marshal.GetLastWin32Error()).Message; + msg = string.Format(ResUI.RegisterGlobalHotkeyFailed, $"{name}({hotkeyInfo.hotkeyStr})", errInfo); + } + UpdateViewEvent?.Invoke(false, msg); + } + + } + } + + public void ReLoad() + { + foreach (var hotkey in _hotkeyTriggerDic.Keys) + { + Application.Current.Dispatcher.Invoke(() => + { + UnregisterHotKey(IntPtr.Zero, hotkey); + }); + } + Init(); + Load(); + } + private (int fsModifiers, int vKey, string hotkeyStr, List Names) GetHotkeyInfo(int hotkeycode) + { + var _fsModifiers = hotkeycode & 0xffff; + var _vkey = (hotkeycode >> 16) & 0xffff; + var _hotkeyStr = new StringBuilder(); + var _names = new List(); + + var mdif = (KeyModifiers)_fsModifiers; + var key = KeyInterop.KeyFromVirtualKey(_vkey); + if ((mdif | KeyModifiers.Ctrl) == KeyModifiers.Ctrl) _hotkeyStr.Append($"{KeyModifiers.Ctrl}+"); + if ((mdif | KeyModifiers.Alt) == KeyModifiers.Alt) _hotkeyStr.Append($"{KeyModifiers.Alt}+"); + if ((mdif | KeyModifiers.Shift) == KeyModifiers.Shift) _hotkeyStr.Append($"{KeyModifiers.Shift}+"); + _hotkeyStr.Append(key.ToString()); + + foreach (var name in _hotkeyTriggerDic[hotkeycode]) + { + _names.Add(name.ToString()); + } + + + return (_fsModifiers, _vkey, _hotkeyStr.ToString(), _names); + } + private void OnThreadPreProcessMessage(ref MSG msg, ref bool handled) + { + if (msg.message != WmHotkey || !_hotkeyTriggerDic.ContainsKey((int)msg.lParam)) + { + return; + } + handled = true; + var _hotKeyCode = (int)msg.lParam; + if (IsPause) + { + Application.Current.Dispatcher.Invoke(() => + { + UIElement? element = Keyboard.FocusedElement as UIElement; + if (element != null) + { + var _keyEventArgs = new KeyEventArgs(Keyboard.PrimaryDevice, + PresentationSource.FromVisual(element), 0, + KeyInterop.KeyFromVirtualKey(GetHotkeyInfo(_hotKeyCode).vKey)) + { + RoutedEvent = UIElement.KeyDownEvent + }; + element.RaiseEvent(_keyEventArgs); + } + }); + } + else + { + foreach (var keyEvent in _hotkeyTriggerDic[(int)msg.lParam]) + { + HotkeyTriggerEvent?.Invoke(keyEvent); + } + } + } + [DllImport("user32.dll", SetLastError = true)] + private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc); + + [DllImport("user32.dll", SetLastError = true)] + private static extern bool UnregisterHotKey(IntPtr hWnd, int id); + [Flags] + private enum KeyModifiers + { + None = 0x0000, + Alt = 0x0001, + Ctrl = 0x0002, + Shift = 0x0004, + Win = 0x0008, + NoRepeat = 0x4000 + } + } +} diff --git a/v2rayN/v2rayN/Handler/LazyConfig.cs b/v2rayN/v2rayN/Handler/LazyConfig.cs index ed915c24..9a2a3ec1 100644 --- a/v2rayN/v2rayN/Handler/LazyConfig.cs +++ b/v2rayN/v2rayN/Handler/LazyConfig.cs @@ -112,7 +112,7 @@ namespace v2rayN.Handler { filter = filter.Replace("'", ""); } - sql += $" and a.remarks like '%{filter}%'"; + sql += String.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter); } return SqliteHelper.Instance.Query(sql).ToList(); diff --git a/v2rayN/v2rayN/Handler/MainFormHandler.cs b/v2rayN/v2rayN/Handler/MainFormHandler.cs index cdf7215c..1e96bd8f 100644 --- a/v2rayN/v2rayN/Handler/MainFormHandler.cs +++ b/v2rayN/v2rayN/Handler/MainFormHandler.cs @@ -1,9 +1,7 @@ -using NHotkey; -using NHotkey.Wpf; + using System.Drawing; using System.IO; using System.Windows.Forms; -using System.Windows.Input; using System.Windows.Media.Imaging; using v2rayN.Mode; using v2rayN.Resx; @@ -343,48 +341,11 @@ namespace v2rayN.Handler } } - public void RegisterGlobalHotkey(Config config, EventHandler handler, Action update) + public void RegisterGlobalHotkey(Config config, Action handler, Action update) { - if (config.globalHotkeys == null) - { - return; - } - - foreach (var item in config.globalHotkeys) - { - if (item.KeyCode == null) - { - continue; - } - - var modifiers = ModifierKeys.None; - if (item.Control) - { - modifiers |= ModifierKeys.Control; - } - if (item.Alt) - { - modifiers |= ModifierKeys.Alt; - } - if (item.Shift) - { - modifiers |= ModifierKeys.Shift; - } - - var gesture = new KeyGesture(KeyInterop.KeyFromVirtualKey((int)item.KeyCode), modifiers); - try - { - HotkeyManager.Current.AddOrReplace(((int)item.eGlobalHotkey).ToString(), gesture, handler); - var msg = string.Format(ResUI.RegisterGlobalHotkeySuccessfully, $"{item.eGlobalHotkey}"); - update(false, msg); - } - catch (Exception ex) - { - var msg = string.Format(ResUI.RegisterGlobalHotkeyFailed, $"{item.eGlobalHotkey}", ex.Message); - update(false, msg); - Utils.SaveLog(msg); - } - } + HotkeyHandler.Instance.UpdateViewEvent += update; + HotkeyHandler.Instance.HotkeyTriggerEvent += handler; + HotkeyHandler.Instance.Load(); } } diff --git a/v2rayN/v2rayN/Mode/ConfigItems.cs b/v2rayN/v2rayN/Mode/ConfigItems.cs index c996f927..18a2e8a3 100644 --- a/v2rayN/v2rayN/Mode/ConfigItems.cs +++ b/v2rayN/v2rayN/Mode/ConfigItems.cs @@ -1,5 +1,4 @@ -using System.Windows.Forms; - +using System.Windows.Input; namespace v2rayN.Mode { [Serializable] @@ -146,7 +145,7 @@ namespace v2rayN.Mode public bool Shift { get; set; } - public Keys? KeyCode { get; set; } + public Key? KeyCode { get; set; } } diff --git a/v2rayN/v2rayN/Mode/ProfileItem.cs b/v2rayN/v2rayN/Mode/ProfileItem.cs index f043dc4f..c26712a2 100644 --- a/v2rayN/v2rayN/Mode/ProfileItem.cs +++ b/v2rayN/v2rayN/Mode/ProfileItem.cs @@ -85,158 +85,100 @@ namespace v2rayN.Mode #endregion [PrimaryKey] - public string indexId - { - get; set; - } + public string indexId { get; set; } /// /// config type(1=normal,2=custom) /// - public EConfigType configType - { - get; set; - } - + public EConfigType configType { get; set; } /// /// 版本(现在=2) /// - public int configVersion - { - get; set; - } + public int configVersion { get; set; } /// /// 远程服务器地址 /// - public string address - { - get; set; - } + public string address { get; set; } /// /// 远程服务器端口 /// - public int port - { - get; set; - } + public int port { get; set; } /// /// 远程服务器ID /// - public string id - { - get; set; - } + public string id { get; set; } /// /// 远程服务器额外ID /// - public int alterId - { - get; set; - } + public int alterId { get; set; } /// /// 本地安全策略 /// - public string security - { - get; set; - } + public string security { get; set; } /// /// tcp,kcp,ws,h2,quic /// - public string network - { - get; set; - } + public string network { get; set; } /// /// 备注或别名 /// - public string remarks - { - get; set; - } + public string remarks { get; set; } /// /// 伪装类型 /// - public string headerType - { - get; set; - } + public string headerType { get; set; } /// /// 伪装的域名 /// - public string requestHost - { - get; set; - } + public string requestHost { get; set; } /// /// ws h2 path /// - public string path - { - get; set; - } + public string path { get; set; } /// /// 传输层安全 /// - public string streamSecurity - { - get; set; - } + public string streamSecurity { get; set; } /// /// 是否允许不安全连接(用于客户端) /// - public string allowInsecure - { - get; set; - } + public string allowInsecure { get; set; } /// /// SubItem id /// - public string subid - { - get; set; - } + public string subid { get; set; } public bool isSub { get; set; } = true; /// /// VLESS flow /// - public string flow - { - get; set; - } + public string flow { get; set; } /// /// tls sni /// - public string sni - { - get; set; - } + public string sni { get; set; } /// /// tls alpn /// public string alpn { get; set; } = string.Empty; - public ECoreType? coreType - { - get; set; - } + public ECoreType? coreType { get; set; } - public int preSocksPort - { - get; set; - } + public int preSocksPort { get; set; } public string fingerprint { get; set; } public bool displayLog { get; set; } = true; + public string publicKey { get; set; } + public string shortId { get; set; } + public string spiderX { get; set; } } } diff --git a/v2rayN/v2rayN/Mode/V2rayConfig.cs b/v2rayN/v2rayN/Mode/V2rayConfig.cs index ec1fd03b..d7436ca8 100644 --- a/v2rayN/v2rayN/Mode/V2rayConfig.cs +++ b/v2rayN/v2rayN/Mode/V2rayConfig.cs @@ -389,9 +389,9 @@ namespace v2rayN.Mode public QuicSettings quicSettings { get; set; } /// - /// VLESS xtls + /// VLESS only /// - public TlsSettings xtlsSettings { get; set; } + public TlsSettings realitySettings { get; set; } /// /// grpc /// @@ -404,24 +404,23 @@ namespace v2rayN.Mode /// /// 是否允许不安全连接(用于客户端) /// - public bool allowInsecure { get; set; } + public bool? allowInsecure { get; set; } /// /// /// - public string serverName { get; set; } + public string? serverName { get; set; } /// /// /// - public List alpn - { - get; set; - } + public List? alpn { get; set; } - /// - /// "chrome" | "firefox" | "safari" | "randomized" - /// - public string fingerprint { get; set; } + public string? fingerprint { get; set; } + + public bool? show { get; set; } = false; + public string? publicKey { get; set; } + public string? shortId { get; set; } + public string? spiderX { get; set; } } diff --git a/v2rayN/v2rayN/Resx/ResUI.Designer.cs b/v2rayN/v2rayN/Resx/ResUI.Designer.cs index 741a2e08..f7237def 100644 --- a/v2rayN/v2rayN/Resx/ResUI.Designer.cs +++ b/v2rayN/v2rayN/Resx/ResUI.Designer.cs @@ -1384,7 +1384,7 @@ namespace v2rayN.Resx { } /// - /// 查找类似 Please fill in the address (Url) 的本地化字符串。 + /// 查找类似 Please fill in the Url 的本地化字符串。 /// public static string MsgNeedUrl { get { @@ -2167,6 +2167,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 PublicKey 的本地化字符串。 + /// + public static string TbPublicKey { + get { + return ResourceManager.GetString("TbPublicKey", resourceCulture); + } + } + /// /// 查找类似 Alias (remarks) 的本地化字符串。 /// @@ -2905,6 +2914,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 ShortId 的本地化字符串。 + /// + public static string TbShortId { + get { + return ResourceManager.GetString("TbShortId", resourceCulture); + } + } + /// /// 查找类似 SNI 的本地化字符串。 /// @@ -2914,6 +2932,15 @@ namespace v2rayN.Resx { } } + /// + /// 查找类似 SpiderX 的本地化字符串。 + /// + public static string TbSpiderX { + get { + return ResourceManager.GetString("TbSpiderX", resourceCulture); + } + } + /// /// 查找类似 TLS 的本地化字符串。 /// diff --git a/v2rayN/v2rayN/Resx/ResUI.resx b/v2rayN/v2rayN/Resx/ResUI.resx index c3b393ad..fa7d6a43 100644 --- a/v2rayN/v2rayN/Resx/ResUI.resx +++ b/v2rayN/v2rayN/Resx/ResUI.resx @@ -380,7 +380,7 @@ Count - Please fill in the address (Url) + Please fill in the Url Do you want to append rules? Choose yes to append, choose otherwise to replace @@ -1132,7 +1132,13 @@ Move up and down - - Enable hardware acceleration(Require restart) + + PublicKey + + + ShortId + + + SpiderX \ No newline at end of file diff --git a/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx b/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx index 243f356b..67798f3e 100644 --- a/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/v2rayN/Resx/ResUI.zh-Hans.resx @@ -304,7 +304,7 @@ 操作失败,请检查重试 - 请填写备注 + 请填写别名 请选择加密方式 @@ -380,7 +380,7 @@ 数量 - 请填写地址(Url) + 请填写Url 是否追加规则?选择是则追加,选择否则替换 @@ -710,7 +710,7 @@ SNI - TLS + 传输层安全(TLS) *默认tcp,选错会无法连接 @@ -1132,7 +1132,13 @@ 移至上下 - - 启用硬件加速(需重启) + + PublicKey + + + ShortId + + + SpiderX \ No newline at end of file diff --git a/v2rayN/v2rayN/ViewModels/AddServerViewModel.cs b/v2rayN/v2rayN/ViewModels/AddServerViewModel.cs index d27c7db4..fbbdb478 100644 --- a/v2rayN/v2rayN/ViewModels/AddServerViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/AddServerViewModel.cs @@ -118,6 +118,10 @@ namespace v2rayN.ViewModels item.allowInsecure = SelectedSource.allowInsecure; item.fingerprint = SelectedSource.fingerprint; item.alpn = SelectedSource.alpn; + + item.publicKey = SelectedSource.publicKey; + item.shortId = SelectedSource.shortId; + item.spiderX = SelectedSource.spiderX; } int ret = -1; diff --git a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs index e50dc36a..a6edad19 100644 --- a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs @@ -3,7 +3,6 @@ using DynamicData.Binding; using MaterialDesignColors; using MaterialDesignColors.ColorManipulation; using MaterialDesignThemes.Wpf; -using NHotkey; using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; @@ -70,6 +69,8 @@ namespace v2rayN.ViewModels public ComboItem SelectedServer { get; set; } [Reactive] public string ServerFilter { get; set; } + [Reactive] + public bool BlServers { get; set; } #endregion #region Menu @@ -630,27 +631,26 @@ namespace v2rayN.ViewModels } } - private void OnHotkeyHandler(object sender, HotkeyEventArgs e) + private void OnHotkeyHandler(EGlobalHotkey e) { - switch (Utils.ToInt(e.Name)) + switch (e) { - case (int)EGlobalHotkey.ShowForm: + case EGlobalHotkey.ShowForm: ShowHideWindow(null); break; - case (int)EGlobalHotkey.SystemProxyClear: + case EGlobalHotkey.SystemProxyClear: SetListenerType(ESysProxyType.ForcedClear); break; - case (int)EGlobalHotkey.SystemProxySet: + case EGlobalHotkey.SystemProxySet: SetListenerType(ESysProxyType.ForcedChange); break; - case (int)EGlobalHotkey.SystemProxyUnchanged: + case EGlobalHotkey.SystemProxyUnchanged: SetListenerType(ESysProxyType.Unchanged); break; - case (int)EGlobalHotkey.SystemProxyPac: + case EGlobalHotkey.SystemProxyPac: SetListenerType(ESysProxyType.Pac); break; } - e.Handled = true; } public void MyAppExit(bool blWindowsShutDown) { @@ -700,7 +700,7 @@ namespace v2rayN.ViewModels _subId = SelectedSub?.id; _config.subIndexId = _subId; - RefreshServers(); + RefreshServers(false); _updateView("ProfilesFocus"); } @@ -715,11 +715,13 @@ namespace v2rayN.ViewModels RefreshServers(); } - private void RefreshServers() + private void RefreshServers(bool blCheckDefault = true) { List lstModel = LazyConfig.Instance.ProfileItems(_subId, _serverFilter); - ConfigHandler.SetDefaultServer(_config, lstModel); - + if (blCheckDefault) + { + ConfigHandler.SetDefaultServer(_config, lstModel); + } List lstServerStat = new(); if (_statistics != null && _statistics.Enable) { @@ -741,6 +743,7 @@ namespace v2rayN.ViewModels security = t.security, network = t.network, streamSecurity = t.streamSecurity, + subid = t.subid, subRemarks = t.subRemarks, isActive = t.indexId == _config.indexId, sort = t33 == null ? 0 : t33.sort, @@ -781,6 +784,11 @@ namespace v2rayN.ViewModels RunningServerDisplay = $"{ResUI.menuServers}:{runningSummary}"; RunningServerToolTipText = runningSummary; } + else + { + RunningServerDisplay = + RunningServerToolTipText = ResUI.CheckServerSettings; + } })); } @@ -789,9 +797,11 @@ namespace v2rayN.ViewModels _servers.Clear(); if (_lstProfile.Count > _config.guiItem.trayMenuServersLimit) { + BlServers = false; return; } + BlServers = true; for (int k = 0; k < _lstProfile.Count; k++) { ProfileItem it = _lstProfile[k]; @@ -828,21 +838,31 @@ namespace v2rayN.ViewModels #endregion #region Add Servers - private int GetProfileItems(out List lstSelecteds) + private int GetProfileItems(out List lstSelecteds, bool latest) { lstSelecteds = new List(); if (SelectedProfiles == null || SelectedProfiles.Count <= 0) { return -1; } - foreach (var profile in SelectedProfiles) + + var orderProfiles = SelectedProfiles?.OrderBy(t => t.sort); + if (latest) { - var item = LazyConfig.Instance.GetProfileItem(profile.indexId); - if (item is not null) + foreach (var profile in orderProfiles) { - lstSelecteds.Add(item); + var item = LazyConfig.Instance.GetProfileItem(profile.indexId); + if (item is not null) + { + lstSelecteds.Add(item); + } } } + else + { + lstSelecteds = Utils.FromJson>(Utils.ToJson(orderProfiles)); + } + return 0; } @@ -929,7 +949,7 @@ namespace v2rayN.ViewModels } public void RemoveServer() { - if (GetProfileItems(out List lstSelecteds) < 0) + if (GetProfileItems(out List lstSelecteds, false) < 0) { return; } @@ -960,7 +980,7 @@ namespace v2rayN.ViewModels } private void CopyServer() { - if (GetProfileItems(out List lstSelecteds) < 0) + if (GetProfileItems(out List lstSelecteds, false) < 0) { return; } @@ -1092,7 +1112,7 @@ namespace v2rayN.ViewModels return; } - if (GetProfileItems(out List lstSelecteds) < 0) + if (GetProfileItems(out List lstSelecteds, false) < 0) { return; } @@ -1143,7 +1163,7 @@ namespace v2rayN.ViewModels { SelectedProfiles = _profileItems; } - if (GetProfileItems(out List lstSelecteds) < 0) + if (GetProfileItems(out List lstSelecteds, false) < 0) { return; } @@ -1175,7 +1195,7 @@ namespace v2rayN.ViewModels public void Export2ShareUrl() { - if (GetProfileItems(out List lstSelecteds) < 0) + if (GetProfileItems(out List lstSelecteds, true) < 0) { return; } @@ -1200,7 +1220,7 @@ namespace v2rayN.ViewModels private void Export2SubContent() { - if (GetProfileItems(out List lstSelecteds) < 0) + if (GetProfileItems(out List lstSelecteds, true) < 0) { return; } diff --git a/v2rayN/v2rayN/Views/AddServerWindow.xaml b/v2rayN/v2rayN/Views/AddServerWindow.xaml index f772794e..991e62a0 100644 --- a/v2rayN/v2rayN/Views/AddServerWindow.xaml +++ b/v2rayN/v2rayN/Views/AddServerWindow.xaml @@ -11,7 +11,7 @@ xmlns:vms="clr-namespace:v2rayN.ViewModels" Title="{x:Static resx:ResUI.menuServers}" Width="800" - Height="800" + Height="830" x:TypeArguments="vms:AddServerViewModel" Background="{DynamicResource MaterialDesignPaper}" FontFamily="{x:Static conv:MaterialDesignFonts.MyFont}" @@ -559,8 +559,10 @@ Margin="{StaticResource ServerItemMargin}" Style="{StaticResource DefComboBox}" /> - - + @@ -595,25 +597,10 @@ Margin="{StaticResource ServerItemMargin}" VerticalAlignment="Center" Style="{StaticResource ToolbarTextBlock}" - Text="{x:Static resx:ResUI.TbAllowInsecure}" /> - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { cmbFingerprint.Items.Add(it); + cmbFingerprint2.Items.Add(it); }); Global.allowInsecures.ForEach(it => { @@ -74,8 +75,8 @@ namespace v2rayN.Views break; case EConfigType.VLESS: gridVLESS.Visibility = Visibility.Visible; - cmbStreamSecurity.Items.Add(Global.StreamSecurityX); - Global.xtlsFlows.ForEach(it => + cmbStreamSecurity.Items.Add(Global.StreamSecurityReality); + Global.flows.ForEach(it => { cmbFlow5.Items.Add(it); }); @@ -86,8 +87,7 @@ namespace v2rayN.Views break; case EConfigType.Trojan: gridTrojan.Visibility = Visibility.Visible; - cmbStreamSecurity.Items.Add(Global.StreamSecurityX); - Global.xtlsFlows.ForEach(it => + Global.flows.ForEach(it => { cmbFlow6.Items.Add(it); }); @@ -138,6 +138,13 @@ namespace v2rayN.Views this.Bind(ViewModel, vm => vm.SelectedSource.allowInsecure, v => v.cmbAllowInsecure.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.fingerprint, v => v.cmbFingerprint.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.alpn, v => v.cmbAlpn.Text).DisposeWith(disposables); + //reality + this.Bind(ViewModel, vm => vm.SelectedSource.sni, v => v.txtSNI2.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedSource.fingerprint, v => v.cmbFingerprint2.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedSource.publicKey, v => v.txtPublicKey.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedSource.shortId, v => v.txtShortId.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedSource.spiderX, v => v.txtSpiderX.Text).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); @@ -159,13 +166,20 @@ namespace v2rayN.Views private void CmbStreamSecurity_SelectionChanged(object sender, SelectionChangedEventArgs e) { var security = cmbStreamSecurity.SelectedItem.ToString(); - if (Utils.IsNullOrEmpty(security)) + if (security == Global.StreamSecurityReality) { + gridRealityMore.Visibility = Visibility.Visible; gridTlsMore.Visibility = Visibility.Hidden; } + else if (security == Global.StreamSecurity) + { + gridRealityMore.Visibility = Visibility.Hidden; + gridTlsMore.Visibility = Visibility.Visible; + } else { - gridTlsMore.Visibility = Visibility.Visible; + gridRealityMore.Visibility = Visibility.Hidden; + gridTlsMore.Visibility = Visibility.Hidden; } } private void btnGUID_Click(object sender, RoutedEventArgs e) diff --git a/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs b/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs index 16cc7fce..830adcb3 100644 --- a/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/GlobalHotkeySettingWindow.xaml.cs @@ -1,47 +1,24 @@ -using System.Windows; +using System.Text; +using System.Windows; using System.Windows.Controls; using System.Windows.Input; using v2rayN.Handler; using v2rayN.Mode; using v2rayN.Resx; -using Forms = System.Windows.Forms; namespace v2rayN.Views { public partial class GlobalHotkeySettingWindow { - private static Config _config; - List lstKey; + private static Config _config = default!; + private Dictionary _TextBoxKeyEventItem = default!; public GlobalHotkeySettingWindow() { InitializeComponent(); this.Owner = Application.Current.MainWindow; _config = LazyConfig.Instance.GetConfig(); - - if (_config.globalHotkeys == null) - { - _config.globalHotkeys = new List(); - } - - foreach (EGlobalHotkey it in Enum.GetValues(typeof(EGlobalHotkey))) - { - if (_config.globalHotkeys.FindIndex(t => t.eGlobalHotkey == it) >= 0) - { - continue; - } - - _config.globalHotkeys.Add(new KeyEventItem() - { - eGlobalHotkey = it, - Alt = false, - Control = false, - Shift = false, - KeyCode = null - }); - } - - lstKey = Utils.DeepCopy(_config.globalHotkeys); + _config.globalHotkeys ??= new List(); txtGlobalHotkey0.KeyDown += TxtGlobalHotkey_KeyDown; txtGlobalHotkey1.KeyDown += TxtGlobalHotkey_KeyDown; @@ -49,69 +26,84 @@ namespace v2rayN.Views txtGlobalHotkey3.KeyDown += TxtGlobalHotkey_KeyDown; txtGlobalHotkey4.KeyDown += TxtGlobalHotkey_KeyDown; - BindingData(-1); - + HotkeyHandler.Instance.IsPause = true; + this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false; Utils.SetDarkBorder(this, _config.uiItem.colorModeDark); + InitData(); + } + + private void InitData() + { + _TextBoxKeyEventItem = new() + { + { txtGlobalHotkey0,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.ShowForm) }, + { txtGlobalHotkey1,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxyClear) }, + { txtGlobalHotkey2,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxySet) }, + { txtGlobalHotkey3,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxyUnchanged)}, + { txtGlobalHotkey4,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxyPac)} + }; + BindingData(); } private void TxtGlobalHotkey_KeyDown(object sender, KeyEventArgs e) { e.Handled = true; - var _ModifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, Key.RightShift, Key.LeftAlt, Key.RightAlt }; - if (!_ModifierKeys.Contains(e.Key) && !_ModifierKeys.Contains(e.SystemKey)) - { - var txt = ((TextBox)sender); - var index = Utils.ToInt(txt.Name.Substring(txt.Name.Length - 1, 1)); - var formsKey = (Forms.Keys)KeyInterop.VirtualKeyFromKey(e.Key == Key.System ? e.SystemKey : e.Key); - - lstKey[index].KeyCode = formsKey; - lstKey[index].Alt = (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt; - lstKey[index].Control = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control; - lstKey[index].Shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift; - - BindingData(index); - } + var _ModifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, + Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin}; + _TextBoxKeyEventItem[sender].KeyCode = e.Key == Key.System ? (_ModifierKeys.Contains(e.SystemKey) ? Key.None : e.SystemKey) : (_ModifierKeys.Contains(e.Key) ? Key.None : e.Key); + _TextBoxKeyEventItem[sender].Alt = (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt; + _TextBoxKeyEventItem[sender].Control = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control; + _TextBoxKeyEventItem[sender].Shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift; + (sender as TextBox)!.Text = KeyEventItemToString(_TextBoxKeyEventItem[sender]); } - private void BindingData(int index) + private KeyEventItem GetKeyEventItemByEGlobalHotkey(List KELsit, EGlobalHotkey eg) { - for (int k = 0; k < lstKey.Count; k++) + return Utils.DeepCopy(KELsit.Find((it) => it.eGlobalHotkey == eg) ?? new() { - if (index >= 0 && index != k) - { - continue; - } - var item = lstKey[k]; - var keys = string.Empty; + eGlobalHotkey = eg, + Control = false, + Alt = false, + Shift = false, + KeyCode = null + }); - if (item.Control) - { - keys += $"{Forms.Keys.Control} + "; - } - if (item.Alt) - { - keys += $"{Forms.Keys.Alt} + "; - } - if (item.Shift) - { - keys += $"{Forms.Keys.Shift} + "; - } - if (item.KeyCode != null) - { - keys += $"{item.KeyCode}"; - } + } + private string KeyEventItemToString(KeyEventItem item) + { + var res = new StringBuilder(); - SetText($"txtGlobalHotkey{k}", keys); + if (item.Control) res.Append($"{ModifierKeys.Control}+"); + if (item.Shift) res.Append($"{ModifierKeys.Shift}+"); + if (item.Alt) res.Append($"{ModifierKeys.Alt}+"); + if (item.KeyCode != null && item.KeyCode != Key.None) + res.Append($"{item.KeyCode}"); + + return res.ToString(); + } + private void BindingData() + { + foreach (var item in _TextBoxKeyEventItem) + { + if (item.Value.KeyCode != null && item.Value.KeyCode != Key.None) + { + (item.Key as TextBox)!.Text = KeyEventItemToString(item.Value); + } + else + { + (item.Key as TextBox)!.Text = string.Empty; + } } } private void btnSave_Click(object sender, RoutedEventArgs e) { - _config.globalHotkeys = lstKey; + _config.globalHotkeys = _TextBoxKeyEventItem.Values.ToList(); if (ConfigHandler.SaveConfig(ref _config, false) == 0) { + HotkeyHandler.Instance.ReLoad(); this.DialogResult = true; } else @@ -127,37 +119,14 @@ namespace v2rayN.Views private void btnReset_Click(object sender, RoutedEventArgs e) { - lstKey.Clear(); - foreach (EGlobalHotkey it in Enum.GetValues(typeof(EGlobalHotkey))) + foreach (var k in _TextBoxKeyEventItem.Keys) { - if (lstKey.FindIndex(t => t.eGlobalHotkey == it) >= 0) - { - continue; - } - - lstKey.Add(new KeyEventItem() - { - eGlobalHotkey = it, - Alt = false, - Control = false, - Shift = false, - KeyCode = null - }); - } - BindingData(-1); - } - private void SetText(string name, string txt) - { - foreach (UIElement element in gridText.Children) - { - if (element is TextBox box) - { - if (box.Name == name) - { - box.Text = txt; - } - } + _TextBoxKeyEventItem[k].Alt = false; + _TextBoxKeyEventItem[k].Control = false; + _TextBoxKeyEventItem[k].Shift = false; + _TextBoxKeyEventItem[k].KeyCode = Key.None; } + BindingData(); } private void GlobalHotkeySettingWindow_KeyDown(object sender, KeyEventArgs e) diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml b/v2rayN/v2rayN/Views/MainWindow.xaml index 1cb9c647..c54166b1 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml +++ b/v2rayN/v2rayN/Views/MainWindow.xaml @@ -617,7 +617,7 @@ - + + + + + + diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml.cs b/v2rayN/v2rayN/Views/MainWindow.xaml.cs index 858f89d2..4483b65a 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/MainWindow.xaml.cs @@ -150,6 +150,7 @@ namespace v2rayN.Views this.OneWayBind(ViewModel, vm => vm.Servers, v => v.cmbServers.ItemsSource).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedServer, v => v.cmbServers.SelectedItem).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlServers, v => v.cmbServers.Visibility).DisposeWith(disposables); //tray menu this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard2).DisposeWith(disposables); @@ -191,7 +192,7 @@ namespace v2rayN.Views this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; spEnableTun.Visibility = IsAdministrator ? Visibility.Visible : Visibility.Collapsed; - + if (_config.uiItem.autoHideStartup) { WindowState = WindowState.Minimized; diff --git a/v2rayN/v2rayN/Views/MsgView.xaml b/v2rayN/v2rayN/Views/MsgView.xaml index af464d31..3a413c7b 100644 --- a/v2rayN/v2rayN/Views/MsgView.xaml +++ b/v2rayN/v2rayN/Views/MsgView.xaml @@ -48,6 +48,7 @@ FontSize="{DynamicResource StdFontSizeMsg}" HorizontalScrollBarVisibility="Auto" IsReadOnly="True" + IsReadOnlyCaretVisible="True" TextAlignment="Left" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"> diff --git a/v2rayN/v2rayN/app.manifest b/v2rayN/v2rayN/app.manifest index c7239fd8..1246cc30 100644 --- a/v2rayN/v2rayN/app.manifest +++ b/v2rayN/v2rayN/app.manifest @@ -6,4 +6,18 @@ PerMonitorV2 + + + + + + + \ No newline at end of file diff --git a/v2rayN/v2rayN/v2rayN.csproj b/v2rayN/v2rayN/v2rayN.csproj index 704d0b5f..2007af72 100644 --- a/v2rayN/v2rayN/v2rayN.csproj +++ b/v2rayN/v2rayN/v2rayN.csproj @@ -10,20 +10,18 @@ enable v2rayN.ico Copyright © 2017-2023 (GPLv3) - 6.15 + 6.17 - - - + - +