Add hotkey setting option.

This commit is contained in:
a90120411 2020-06-14 22:42:14 +08:00
parent a799420d0f
commit c720ef756b
23 changed files with 3424 additions and 1849 deletions

View file

@ -78,6 +78,7 @@
this.menuScanScreen2 = new System.Windows.Forms.ToolStripMenuItem();
this.menuCopyPACUrl = new System.Windows.Forms.ToolStripMenuItem();
this.menuUpdateSubscriptions = new System.Windows.Forms.ToolStripMenuItem();
this.menuQuicklyAddUserPAC = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
this.menuExit = new System.Windows.Forms.ToolStripMenuItem();
this.bgwScan = new System.ComponentModel.BackgroundWorker();
@ -400,6 +401,7 @@
this.menuScanScreen2,
this.menuCopyPACUrl,
this.menuUpdateSubscriptions,
this.menuQuicklyAddUserPAC,
this.toolStripSeparator2,
this.menuExit});
this.cmsMain.Name = "contextMenuStrip1";
@ -491,6 +493,12 @@
resources.ApplyResources(this.menuUpdateSubscriptions, "menuUpdateSubscriptions");
this.menuUpdateSubscriptions.Click += new System.EventHandler(this.menuUpdateSubscriptions_Click);
//
// menuQuicklyAddUserPAC
//
this.menuQuicklyAddUserPAC.Name = "menuQuicklyAddUserPAC";
resources.ApplyResources(this.menuQuicklyAddUserPAC, "menuQuicklyAddUserPAC");
this.menuQuicklyAddUserPAC.Click += new System.EventHandler(this.menuQuicklyAddUserPAC_Click);
//
// toolStripSeparator2
//
this.toolStripSeparator2.Name = "toolStripSeparator2";
@ -936,6 +944,7 @@
private System.Windows.Forms.ToolStripMenuItem tsbTestMe;
private System.Windows.Forms.ToolStripButton tsbReload;
private System.Windows.Forms.ToolStripButton tsbQRCodeSwitch;
private System.Windows.Forms.ToolStripMenuItem menuQuicklyAddUserPAC;
}
}

View file

@ -11,6 +11,7 @@ using v2rayN.Tool;
using System.Diagnostics;
using System.Drawing;
using System.Net;
using v2rayN.Handler.Hotkey;
namespace v2rayN.Forms
{
@ -19,6 +20,7 @@ namespace v2rayN.Forms
private V2rayHandler v2rayHandler;
private List<int> lvSelecteds = new List<int>();
private StatisticsHandler statistics = null;
private QuicklyAddUserPACForm fmQuickAddUserPAC;
#region Window
@ -49,6 +51,18 @@ namespace v2rayN.Forms
ConfigHandler.LoadConfig(ref config);
v2rayHandler = new V2rayHandler();
v2rayHandler.ProcessEvent += v2rayHandler_ProcessEvent;
v2rayHandler.StopProxyEvent += this.menuNotEnabledHttp_Click;
v2rayHandler.StartGlobalProxyModeEvent += this.menuGlobal_Click;
v2rayHandler.StartPACProxyModeEvent += this.menuGlobalPAC_Click;
v2rayHandler.ShowAddUserPACEvent += this.menuQuicklyAddUserPAC_Click;
Hotkeys.Init(v2rayHandler);
if (config.hotkeyConfig.regHotkeyAtStartup)
{
HotkeyReg.RegAllHotkeys(config.hotkeyConfig);
}
if (config.enableStatistics)
{
@ -1217,6 +1231,28 @@ namespace v2rayN.Forms
{
SetListenerType(ListenerType.PacOpenOnly);
}
private void menuQuicklyAddUserPAC_Click(object sender, EventArgs e)
{
if (fmQuickAddUserPAC == null)
{
fmQuickAddUserPAC = new QuicklyAddUserPACForm();
}
if (fmQuickAddUserPAC.Visible == false)
{
fmQuickAddUserPAC.ShowDialog();
}
else
{
fmQuickAddUserPAC.Activate();
}
if (fmQuickAddUserPAC.DialogResult == DialogResult.OK)
{
//刷新
LoadV2ray();
}
}
private void SetListenerType(ListenerType type)
{
config.listenerType = type;

View file

@ -506,6 +506,12 @@
<data name="menuUpdateSubscriptions.Text" xml:space="preserve">
<value>Update subscriptions</value>
</data>
<data name="menuQuicklyAddUserPAC.Size" type="System.Drawing.Size, System.Drawing">
<value>264, 22</value>
</data>
<data name="menuQuicklyAddUserPAC.Text" xml:space="preserve">
<value>Quickly add user PAC rule</value>
</data>
<data name="toolStripSeparator2.Size" type="System.Drawing.Size, System.Drawing">
<value>261, 6</value>
</data>
@ -516,7 +522,7 @@
<value>Exit</value>
</data>
<data name="cmsMain.Size" type="System.Drawing.Size, System.Drawing">
<value>265, 164</value>
<value>265, 208</value>
</data>
<data name="&gt;&gt;cmsMain.Name" xml:space="preserve">
<value>cmsMain</value>
@ -1250,6 +1256,12 @@
<data name="&gt;&gt;menuUpdateSubscriptions.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;menuQuicklyAddUserPAC.Name" xml:space="preserve">
<value>menuQuicklyAddUserPAC</value>
</data>
<data name="&gt;&gt;menuQuicklyAddUserPAC.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;toolStripSeparator2.Name" xml:space="preserve">
<value>toolStripSeparator2</value>
</data>

View file

@ -372,6 +372,12 @@
<data name="menuUpdateSubscriptions.Text" xml:space="preserve">
<value>更新订阅</value>
</data>
<data name="menuQuicklyAddUserPAC.Size" type="System.Drawing.Size, System.Drawing">
<value>195, 22</value>
</data>
<data name="menuQuicklyAddUserPAC.Text" xml:space="preserve">
<value>添加一条用户PAC规则</value>
</data>
<data name="toolStripSeparator2.Size" type="System.Drawing.Size, System.Drawing">
<value>192, 6</value>
</data>

View file

@ -97,6 +97,16 @@
this.txtuserPacRule = new System.Windows.Forms.TextBox();
this.panel4 = new System.Windows.Forms.Panel();
this.label4 = new System.Windows.Forms.Label();
this.tabPage10 = new System.Windows.Forms.TabPage();
this.chkRegHotkeyAtStartup = new System.Windows.Forms.CheckBox();
this.txtHotkeyAddUserPAC = new System.Windows.Forms.TextBox();
this.lblHotkeyAddUserPAC = new System.Windows.Forms.Label();
this.txtHotkeyPACProxyMode = new System.Windows.Forms.TextBox();
this.lblHotkeyPACProxyMode = new System.Windows.Forms.Label();
this.txtHotkeyGlobalProxyMode = new System.Windows.Forms.TextBox();
this.lblHotkeyGlobalProxyMode = new System.Windows.Forms.Label();
this.txtHotkeyStopProxy = new System.Windows.Forms.TextBox();
this.lblHotkeyStopProxy = new System.Windows.Forms.Label();
this.panel2 = new System.Windows.Forms.Panel();
this.btnOK = new System.Windows.Forms.Button();
this.panel1 = new System.Windows.Forms.Panel();
@ -115,6 +125,7 @@
this.tabPage7.SuspendLayout();
this.tabPage9.SuspendLayout();
this.panel4.SuspendLayout();
this.tabPage10.SuspendLayout();
this.panel2.SuspendLayout();
this.SuspendLayout();
//
@ -134,6 +145,7 @@
this.tabControl1.Controls.Add(this.tabPage6);
this.tabControl1.Controls.Add(this.tabPage7);
this.tabControl1.Controls.Add(this.tabPage9);
this.tabControl1.Controls.Add(this.tabPage10);
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
//
@ -603,6 +615,83 @@
this.label4.ForeColor = System.Drawing.Color.Brown;
this.label4.Name = "label4";
//
// tabPage10
//
resources.ApplyResources(this.tabPage10, "tabPage10");
this.tabPage10.Controls.Add(this.chkRegHotkeyAtStartup);
this.tabPage10.Controls.Add(this.txtHotkeyAddUserPAC);
this.tabPage10.Controls.Add(this.lblHotkeyAddUserPAC);
this.tabPage10.Controls.Add(this.txtHotkeyPACProxyMode);
this.tabPage10.Controls.Add(this.lblHotkeyPACProxyMode);
this.tabPage10.Controls.Add(this.txtHotkeyGlobalProxyMode);
this.tabPage10.Controls.Add(this.lblHotkeyGlobalProxyMode);
this.tabPage10.Controls.Add(this.txtHotkeyStopProxy);
this.tabPage10.Controls.Add(this.lblHotkeyStopProxy);
this.tabPage10.Name = "tabPage10";
this.tabPage10.UseVisualStyleBackColor = true;
//
// chkRegHotkeyAtStartup
//
resources.ApplyResources(this.chkRegHotkeyAtStartup, "chkRegHotkeyAtStartup");
this.chkRegHotkeyAtStartup.Name = "chkRegHotkeyAtStartup";
this.chkRegHotkeyAtStartup.UseVisualStyleBackColor = true;
//
// txtHotkeyAddUserPAC
//
resources.ApplyResources(this.txtHotkeyAddUserPAC, "txtHotkeyAddUserPAC");
this.txtHotkeyAddUserPAC.BackColor = System.Drawing.SystemColors.Window;
this.txtHotkeyAddUserPAC.Name = "txtHotkeyAddUserPAC";
this.txtHotkeyAddUserPAC.ReadOnly = true;
this.txtHotkeyAddUserPAC.KeyDown += new System.Windows.Forms.KeyEventHandler(this.HotkeyDown);
this.txtHotkeyAddUserPAC.KeyUp += new System.Windows.Forms.KeyEventHandler(this.HotkeyUp);
//
// lblHotkeyAddUserPAC
//
resources.ApplyResources(this.lblHotkeyAddUserPAC, "lblHotkeyAddUserPAC");
this.lblHotkeyAddUserPAC.Name = "lblHotkeyAddUserPAC";
//
// txtHotkeyPACProxyMode
//
resources.ApplyResources(this.txtHotkeyPACProxyMode, "txtHotkeyPACProxyMode");
this.txtHotkeyPACProxyMode.BackColor = System.Drawing.SystemColors.Window;
this.txtHotkeyPACProxyMode.Name = "txtHotkeyPACProxyMode";
this.txtHotkeyPACProxyMode.ReadOnly = true;
this.txtHotkeyPACProxyMode.KeyDown += new System.Windows.Forms.KeyEventHandler(this.HotkeyDown);
this.txtHotkeyPACProxyMode.KeyUp += new System.Windows.Forms.KeyEventHandler(this.HotkeyUp);
//
// lblHotkeyPACProxyMode
//
resources.ApplyResources(this.lblHotkeyPACProxyMode, "lblHotkeyPACProxyMode");
this.lblHotkeyPACProxyMode.Name = "lblHotkeyPACProxyMode";
//
// txtHotkeyGlobalProxyMode
//
resources.ApplyResources(this.txtHotkeyGlobalProxyMode, "txtHotkeyGlobalProxyMode");
this.txtHotkeyGlobalProxyMode.BackColor = System.Drawing.SystemColors.Window;
this.txtHotkeyGlobalProxyMode.Name = "txtHotkeyGlobalProxyMode";
this.txtHotkeyGlobalProxyMode.ReadOnly = true;
this.txtHotkeyGlobalProxyMode.KeyDown += new System.Windows.Forms.KeyEventHandler(this.HotkeyDown);
this.txtHotkeyGlobalProxyMode.KeyUp += new System.Windows.Forms.KeyEventHandler(this.HotkeyUp);
//
// lblHotkeyGlobalProxyMode
//
resources.ApplyResources(this.lblHotkeyGlobalProxyMode, "lblHotkeyGlobalProxyMode");
this.lblHotkeyGlobalProxyMode.Name = "lblHotkeyGlobalProxyMode";
//
// txtHotkeyStopProxy
//
resources.ApplyResources(this.txtHotkeyStopProxy, "txtHotkeyStopProxy");
this.txtHotkeyStopProxy.BackColor = System.Drawing.SystemColors.Window;
this.txtHotkeyStopProxy.Name = "txtHotkeyStopProxy";
this.txtHotkeyStopProxy.ReadOnly = true;
this.txtHotkeyStopProxy.KeyDown += new System.Windows.Forms.KeyEventHandler(this.HotkeyDown);
this.txtHotkeyStopProxy.KeyUp += new System.Windows.Forms.KeyEventHandler(this.HotkeyUp);
//
// lblHotkeyStopProxy
//
resources.ApplyResources(this.lblHotkeyStopProxy, "lblHotkeyStopProxy");
this.lblHotkeyStopProxy.Name = "lblHotkeyStopProxy";
//
// panel2
//
resources.ApplyResources(this.panel2, "panel2");
@ -656,6 +745,8 @@
this.tabPage9.ResumeLayout(false);
this.tabPage9.PerformLayout();
this.panel4.ResumeLayout(false);
this.tabPage10.ResumeLayout(false);
this.tabPage10.PerformLayout();
this.panel2.ResumeLayout(false);
this.ResumeLayout(false);
@ -734,5 +825,15 @@
private System.Windows.Forms.CheckBox chkKeepOlderDedupl;
private System.Windows.Forms.LinkLabel linkLabelRoutingDoc;
private System.Windows.Forms.CheckBox chkdefAllowInsecure;
private System.Windows.Forms.TabPage tabPage10;
private System.Windows.Forms.TextBox txtHotkeyAddUserPAC;
private System.Windows.Forms.Label lblHotkeyAddUserPAC;
private System.Windows.Forms.TextBox txtHotkeyPACProxyMode;
private System.Windows.Forms.Label lblHotkeyPACProxyMode;
private System.Windows.Forms.TextBox txtHotkeyGlobalProxyMode;
private System.Windows.Forms.Label lblHotkeyGlobalProxyMode;
private System.Windows.Forms.TextBox txtHotkeyStopProxy;
private System.Windows.Forms.Label lblHotkeyStopProxy;
private System.Windows.Forms.CheckBox chkRegHotkeyAtStartup;
}
}

View file

@ -4,6 +4,10 @@ using System.Windows.Forms;
using v2rayN.Handler;
using v2rayN.Base;
using v2rayN.HttpProxyHandler;
using System.Text;
using static v2rayN.Handler.Hotkey.HotkeyReg;
using v2rayN.Handler.Hotkey;
using System.Drawing;
namespace v2rayN.Forms
{
@ -25,6 +29,8 @@ namespace v2rayN.Forms
InitGUI();
InitUserPAC();
InitHotkey();
}
/// <summary>
@ -151,6 +157,15 @@ namespace v2rayN.Forms
txtuserPacRule.Text = Utils.List2String(config.userPacRule, true);
}
private void InitHotkey()
{
txtHotkeyStopProxy.Text = config.hotkeyConfig.stopProxy;
txtHotkeyGlobalProxyMode.Text = config.hotkeyConfig.globalProxyMode;
txtHotkeyPACProxyMode.Text = config.hotkeyConfig.pacProxyMode;
txtHotkeyAddUserPAC.Text = config.hotkeyConfig.addUserPAC;
chkRegHotkeyAtStartup.Checked = config.hotkeyConfig.regHotkeyAtStartup;
}
private void btnOK_Click(object sender, EventArgs e)
{
if (SaveBase() != 0)
@ -178,6 +193,11 @@ namespace v2rayN.Forms
return;
}
if (SaveHotkey() != 0)
{
return;
}
if (ConfigHandler.SaveConfig(ref config) == 0)
{
this.DialogResult = DialogResult.OK;
@ -371,6 +391,23 @@ namespace v2rayN.Forms
return 0;
}
private int SaveHotkey()
{
if (!RegisterAllHotkeys())
{
return -1;
}
config.hotkeyConfig.stopProxy = txtHotkeyStopProxy.Text;
config.hotkeyConfig.globalProxyMode = txtHotkeyGlobalProxyMode.Text;
config.hotkeyConfig.pacProxyMode = txtHotkeyPACProxyMode.Text;
config.hotkeyConfig.addUserPAC = txtHotkeyAddUserPAC.Text;
config.hotkeyConfig.regHotkeyAtStartup = chkRegHotkeyAtStartup.Checked;
return 0;
}
private void btnClose_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
@ -446,6 +483,92 @@ namespace v2rayN.Forms
{
System.Diagnostics.Process.Start("https://www.v2fly.org/chapter_02/03_routing.html");
}
/// <summary>
/// Capture hotkey - Press key
/// </summary>
private void HotkeyDown(object sender, KeyEventArgs e)
{
StringBuilder sb = new StringBuilder();
//Combination key only
if (e.Modifiers != 0)
{
// XXX: Hotkey parsing depends on the sequence, more specifically, ModifierKeysConverter.
// Windows key is reserved by operating system, we deny this key.
if (e.Control)
{
sb.Append("Ctrl+");
}
if (e.Alt)
{
sb.Append("Alt+");
}
if (e.Shift)
{
sb.Append("Shift+");
}
Keys keyvalue = (Keys)e.KeyValue;
if ((keyvalue >= Keys.PageUp && keyvalue <= Keys.Down) ||
(keyvalue >= Keys.A && keyvalue <= Keys.Z) ||
(keyvalue >= Keys.F1 && keyvalue <= Keys.F12))
{
sb.Append(e.KeyCode);
}
else if (keyvalue >= Keys.D0 && keyvalue <= Keys.D9)
{
sb.Append('D').Append((char)e.KeyValue);
}
else if (keyvalue >= Keys.NumPad0 && keyvalue <= Keys.NumPad9)
{
sb.Append("NumPad").Append((char)(e.KeyValue - 48));
}
}
((TextBox)sender).Text = sb.ToString();
}
/// <summary>
/// Capture hotkey - Release key
/// </summary>
private void HotkeyUp(object sender, KeyEventArgs e)
{
var tb = (TextBox)sender;
var content = tb.Text.TrimEnd();
if (content.Length >= 1 && content[content.Length - 1] == '+')
{
tb.Text = "";
}
}
private bool RegisterAllHotkeys()
{
return
RegHotkeyFromString(txtHotkeyStopProxy.Text, "StopProxyCallback", result => HandleRegResult(txtHotkeyStopProxy.Text, lblHotkeyStopProxy, result))
&& RegHotkeyFromString(txtHotkeyGlobalProxyMode.Text, "GlobalProxyModeCallback", result => HandleRegResult(txtHotkeyGlobalProxyMode.Text, lblHotkeyGlobalProxyMode, result))
&& RegHotkeyFromString(txtHotkeyPACProxyMode.Text, "PACProxyModeCallback", result => HandleRegResult(txtHotkeyPACProxyMode.Text, lblHotkeyPACProxyMode, result))
&& RegHotkeyFromString(txtHotkeyAddUserPAC.Text, "AddUserPACCallback", result => HandleRegResult(txtHotkeyAddUserPAC.Text, lblHotkeyAddUserPAC, result));
}
private void HandleRegResult(string hotkeyStr, Label label, HotkeyReg.RegResult result)
{
switch (result)
{
case RegResult.ParseError:
UI.ShowWarning(string.Format(UIRes.I18N("HotkeyParseFailed"), hotkeyStr));
break;
case RegResult.UnregSuccess:
label.ResetBackColor();
break;
case RegResult.RegSuccess:
label.BackColor = Color.Green;
break;
case RegResult.RegFailure:
label.BackColor = Color.Red;
break;
default:
break;
}
}
}
class ComboItem

File diff suppressed because it is too large Load diff

View file

@ -369,6 +369,57 @@
<data name="label4.Text" xml:space="preserve">
<value>*设置用户PAC规则用逗号(,)隔开</value>
</data>
<data name="tabPage10.Text" xml:space="preserve">
<value> 快捷键设置 </value>
</data>
<data name="chkRegHotkeyAtStartup.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="chkRegHotkeyAtStartup.Location" type="System.Drawing.Point, System.Drawing">
<value>16, 160</value>
</data>
<data name="chkRegHotkeyAtStartup.Size" type="System.Drawing.Size, System.Drawing">
<value>144, 16</value>
</data>
<data name="chkRegHotkeyAtStartup.Text" xml:space="preserve">
<value>启动时注册所有快捷键</value>
</data>
<data name="txtHotkeyAddUserPAC.Location" type="System.Drawing.Point, System.Drawing">
<value>146, 121</value>
</data>
<data name="lblHotkeyAddUserPAC.Size" type="System.Drawing.Size, System.Drawing">
<value>95, 12</value>
</data>
<data name="lblHotkeyAddUserPAC.Text" xml:space="preserve">
<value>添加用户PAC记录</value>
</data>
<data name="txtHotkeyPACProxyMode.Location" type="System.Drawing.Point, System.Drawing">
<value>146, 85</value>
</data>
<data name="lblHotkeyPACProxyMode.Size" type="System.Drawing.Size, System.Drawing">
<value>119, 12</value>
</data>
<data name="lblHotkeyPACProxyMode.Text" xml:space="preserve">
<value>开启使用PAC代理模式</value>
</data>
<data name="txtHotkeyGlobalProxyMode.Location" type="System.Drawing.Point, System.Drawing">
<value>146, 50</value>
</data>
<data name="lblHotkeyGlobalProxyMode.Size" type="System.Drawing.Size, System.Drawing">
<value>125, 12</value>
</data>
<data name="lblHotkeyGlobalProxyMode.Text" xml:space="preserve">
<value>开启使用全局代理模式</value>
</data>
<data name="txtHotkeyStopProxy.Location" type="System.Drawing.Point, System.Drawing">
<value>146, 15</value>
</data>
<data name="lblHotkeyStopProxy.Size" type="System.Drawing.Size, System.Drawing">
<value>77, 12</value>
</data>
<data name="lblHotkeyStopProxy.Text" xml:space="preserve">
<value>关闭代理服务</value>
</data>
<data name="btnOK.Text" xml:space="preserve">
<value>确定(&amp;O)</value>
</data>

View file

@ -0,0 +1,89 @@
namespace v2rayN.Forms
{
partial class QuicklyAddUserPACForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(QuicklyAddUserPACForm));
this.label6 = new System.Windows.Forms.Label();
this.txtUserPACRule = new System.Windows.Forms.TextBox();
this.btnClose = new System.Windows.Forms.Button();
this.btnOK = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// label6
//
resources.ApplyResources(this.label6, "label6");
this.label6.Name = "label6";
//
// txtUserPACRule
//
resources.ApplyResources(this.txtUserPACRule, "txtUserPACRule");
this.txtUserPACRule.Name = "txtUserPACRule";
//
// btnClose
//
this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
resources.ApplyResources(this.btnClose, "btnClose");
this.btnClose.Name = "btnClose";
this.btnClose.UseVisualStyleBackColor = true;
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
//
// btnOK
//
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
resources.ApplyResources(this.btnOK, "btnOK");
this.btnOK.Name = "btnOK";
this.btnOK.UseVisualStyleBackColor = true;
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
//
// QuicklyAddUserPACForm
//
this.AcceptButton = this.btnOK;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnClose;
this.Controls.Add(this.btnClose);
this.Controls.Add(this.btnOK);
this.Controls.Add(this.txtUserPACRule);
this.Controls.Add(this.label6);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Name = "QuicklyAddUserPACForm";
this.VisibleChanged += new System.EventHandler(this.QuicklyAddUserPACForm_VisibleChanged);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label6;
private System.Windows.Forms.TextBox txtUserPACRule;
private System.Windows.Forms.Button btnClose;
private System.Windows.Forms.Button btnOK;
}
}

View file

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using v2rayN.Base;
namespace v2rayN.Forms
{
public partial class QuicklyAddUserPACForm : BaseForm
{
public QuicklyAddUserPACForm()
{
InitializeComponent();
}
private void btnOK_Click(object sender, EventArgs e)
{
string userPacRule=this.txtUserPACRule.Text.TrimEx().Replace("\"", "");
this.txtUserPACRule.Text = "";
if (!string.IsNullOrEmpty(userPacRule))
{
config.userPacRule.Insert(0, userPacRule);
this.DialogResult = DialogResult.OK;
}
else
{
this.DialogResult = DialogResult.Cancel;
}
}
private void btnClose_Click(object sender, EventArgs e)
{
this.txtUserPACRule.Text = "";
this.DialogResult = DialogResult.Cancel;
}
private void QuicklyAddUserPACForm_VisibleChanged(object sender, EventArgs e)
{
//在主屏幕的左下角显示窗口
if (this.Visible == true)
{
int heightLocation = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Size.Height - this.Size.Height - 10;
this.SetDesktopLocation(12, heightLocation);
this.Activate();
}
this.txtUserPACRule.Focus();
}
}
}

View file

@ -0,0 +1,249 @@
<?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="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="label6.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="label6.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="label6.Location" type="System.Drawing.Point, System.Drawing">
<value>10, 12</value>
</data>
<data name="label6.Size" type="System.Drawing.Size, System.Drawing">
<value>83, 12</value>
</data>
<data name="label6.TabIndex" type="System.Int32, mscorlib">
<value>11</value>
</data>
<data name="label6.Text" xml:space="preserve">
<value>User PAC rule</value>
</data>
<data name="&gt;&gt;label6.Name" xml:space="preserve">
<value>label6</value>
</data>
<data name="&gt;&gt;label6.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;label6.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;label6.ZOrder" xml:space="preserve">
<value>3</value>
</data>
<data name="txtUserPACRule.Location" type="System.Drawing.Point, System.Drawing">
<value>12, 37</value>
</data>
<data name="txtUserPACRule.Size" type="System.Drawing.Size, System.Drawing">
<value>341, 21</value>
</data>
<data name="txtUserPACRule.TabIndex" type="System.Int32, mscorlib">
<value>12</value>
</data>
<data name="&gt;&gt;txtUserPACRule.Name" xml:space="preserve">
<value>txtUserPACRule</value>
</data>
<data name="&gt;&gt;txtUserPACRule.Type" xml:space="preserve">
<value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;txtUserPACRule.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;txtUserPACRule.ZOrder" xml:space="preserve">
<value>2</value>
</data>
<data name="btnClose.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="btnClose.Location" type="System.Drawing.Point, System.Drawing">
<value>278, 72</value>
</data>
<data name="btnClose.Size" type="System.Drawing.Size, System.Drawing">
<value>75, 23</value>
</data>
<data name="btnClose.TabIndex" type="System.Int32, mscorlib">
<value>14</value>
</data>
<data name="btnClose.Text" xml:space="preserve">
<value>&amp;Cancel</value>
</data>
<data name="&gt;&gt;btnClose.Name" xml:space="preserve">
<value>btnClose</value>
</data>
<data name="&gt;&gt;btnClose.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;btnClose.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;btnClose.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="btnOK.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="btnOK.Location" type="System.Drawing.Point, System.Drawing">
<value>195, 72</value>
</data>
<data name="btnOK.Size" type="System.Drawing.Size, System.Drawing">
<value>75, 23</value>
</data>
<data name="btnOK.TabIndex" type="System.Int32, mscorlib">
<value>13</value>
</data>
<data name="btnOK.Text" xml:space="preserve">
<value>&amp;OK</value>
</data>
<data name="&gt;&gt;btnOK.Name" xml:space="preserve">
<value>btnOK</value>
</data>
<data name="&gt;&gt;btnOK.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;btnOK.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;btnOK.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="$this.Localizable" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
<value>6, 12</value>
</data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>365, 106</value>
</data>
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
<value>Manual</value>
</data>
<data name="$this.Text" xml:space="preserve">
<value>Quickly add user PAC rule</value>
</data>
<data name="&gt;&gt;$this.Name" xml:space="preserve">
<value>QuicklyAddUserPACForm</value>
</data>
<data name="&gt;&gt;$this.Type" xml:space="preserve">
<value>v2rayN.Forms.BaseForm, v2rayN, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</value>
</data>
</root>

View file

@ -0,0 +1,143 @@
<?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.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="label6.Size" type="System.Drawing.Size, System.Drawing">
<value>95, 12</value>
</data>
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="label6.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
</data>
<data name="label6.Text" xml:space="preserve">
<value>用户PAC规则地址</value>
</data>
<data name="txtUserPACRule.TabIndex" type="System.Int32, mscorlib">
<value>11</value>
</data>
<data name="btnClose.Text" xml:space="preserve">
<value>取消</value>
</data>
<data name="btnOK.Text" xml:space="preserve">
<value>确定</value>
</data>
<data name="$this.Text" xml:space="preserve">
<value>快速添加用户PAC规则</value>
</data>
</root>

View file

@ -156,6 +156,10 @@ namespace v2rayN.Handler
{
config.userPacRule = new List<string>();
}
if (config.hotkeyConfig == null)
{
config.hotkeyConfig = new HotkeyConfig();
}
if (config == null
|| config.index < 0

View file

@ -0,0 +1,82 @@
using System;
using System.Reflection;
namespace v2rayN.Handler.Hotkey
{
public class HotkeyCallbacks
{
public static void InitInstance(V2rayHandler v2rayHandler)
{
if (Instance != null)
{
return;
}
Instance = new HotkeyCallbacks(v2rayHandler);
}
/// <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 V2rayHandler _v2rayHandler;
private HotkeyCallbacks(V2rayHandler v2rayHandler)
{
_v2rayHandler = v2rayHandler;
}
#endregion
#region Callbacks
/// <summary>
/// 停止系统代理服务
/// </summary>
private void StopProxyCallback()
{
_v2rayHandler.StopProxy();
}
/// <summary>
/// 开启使用全局代理服务模式
/// </summary>
private void GlobalProxyModeCallback()
{
_v2rayHandler.StartUseGlobalProxyMode();
}
/// <summary>
/// 开启使用PAC代理服务模式
/// </summary>
private void PACProxyModeCallback()
{
_v2rayHandler.StartUsePACProxyMode();
}
/// <summary>
/// 快速添加用户PAC规则
/// </summary>
private void AddUserPACCallback()
{
_v2rayHandler.ShowAddUserPACForm();
}
#endregion
}
}

View file

@ -0,0 +1,82 @@
using System;
using System.Windows.Forms;
using v2rayN.Mode;
namespace v2rayN.Handler.Hotkey
{
public static class HotkeyReg
{
public static void RegAllHotkeys(HotkeyConfig hotkeyConfig)
{
if (hotkeyConfig == null || !hotkeyConfig.regHotkeyAtStartup)
return;
// if any of the hotkey reg fail, undo everything
if (RegHotkeyFromString(hotkeyConfig.stopProxy, "StopProxyCallback")
&& RegHotkeyFromString(hotkeyConfig.globalProxyMode, "GlobalProxyModeCallback")
&& RegHotkeyFromString(hotkeyConfig.pacProxyMode, "PACProxyModeCallback")
&& RegHotkeyFromString(hotkeyConfig.addUserPAC, "AddUserPACCallback")
)
{
// success
}
else
{
RegHotkeyFromString("", "StopProxyCallback");
RegHotkeyFromString("", "GlobalProxyModeCallback");
RegHotkeyFromString("", "PACProxyModeCallback");
RegHotkeyFromString("", "AddUserPACCallback");
UI.ShowWarning(UIRes.I18N("HotkeyRegFailed"));
}
}
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)
{
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
}
}
}

View file

@ -0,0 +1,175 @@
using GlobalHotKey;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Input;
using v2rayN.Mode;
namespace v2rayN.Handler.Hotkey
{
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(V2rayHandler v2rayHandler)
{
_hotKeyManager = new HotKeyManager();
_hotKeyManager.KeyPressed += HotKeyManagerPressed;
HotkeyCallbacks.InitInstance(v2rayHandler);
}
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);
}
}
}

View file

@ -18,11 +18,17 @@ namespace v2rayN.Handler
/// <summary>
/// v2ray进程处理类
/// </summary>
class V2rayHandler
public class V2rayHandler
{
private static string v2rayConfigRes = Global.v2rayConfigFileName;
private List<string> lstV2ray;
public event ProcessDelegate ProcessEvent;
public event EventHandler StopProxyEvent;
public event EventHandler StartGlobalProxyModeEvent;
public event EventHandler StartPACProxyModeEvent;
public event EventHandler ShowAddUserPACEvent;
//private int processId = 0;
private Process _process;
@ -300,6 +306,23 @@ namespace v2rayN.Handler
{
ProcessEvent?.Invoke(updateToTrayTooltip, msg);
}
public void StopProxy()
{
StopProxyEvent?.Invoke(null, null);
}
public void StartUseGlobalProxyMode()
{
StartGlobalProxyModeEvent?.Invoke(null, null);
}
public void StartUsePACProxyMode()
{
StartPACProxyModeEvent?.Invoke(null, null);
}
public void ShowAddUserPACForm()
{
ShowAddUserPACEvent?.Invoke(null, null);
}
private void KillProcess(Process p)
{

View file

@ -207,6 +207,14 @@ namespace v2rayN.Mode
get; set;
}
/// <summary>
/// 快捷键设置
/// </summary>
public HotkeyConfig hotkeyConfig
{
get; set;
}
#region
public string address()
@ -716,4 +724,38 @@ namespace v2rayN.Mode
get; set;
}
}
[Serializable]
public class HotkeyConfig
{
/// <summary>
/// 停止代理服务的快捷键
/// </summary>
public string stopProxy { get; set; }
/// <summary>
/// 开启使用全局代理服务的快捷键
/// </summary>
public string globalProxyMode { get; set; }
/// <summary>
/// 开启使用PAC代理模式的快捷键
/// </summary>
public string pacProxyMode { get; set; }
/// <summary>
/// 打开添加一条用户PAC规则窗口的快捷键
/// </summary>
public string addUserPAC { get; set; }
/// <summary>
/// 是否在程序启动时注册所有的快捷键
/// </summary>
public bool regHotkeyAtStartup { get; set; }
public HotkeyConfig()
{
stopProxy = "";
globalProxyMode = "";
pacProxyMode = "";
addUserPAC = "";
regHotkeyAtStartup = false;
}
}
}

View file

@ -32,4 +32,4 @@ using System.Runtime.InteropServices;
// 方法是按如下所示使用“*”:
//[assembly: AssemblyVersion("1.0.*")]
//[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyFileVersion("3.19")]
[assembly: AssemblyFileVersion("3.20")]

View file

@ -240,6 +240,24 @@ namespace v2rayN.Resx {
}
}
/// <summary>
/// 查找类似 Cannot parse hotkey: {0} 的本地化字符串。
/// </summary>
internal static string HotkeyParseFailed {
get {
return ResourceManager.GetString("HotkeyParseFailed", resourceCulture);
}
}
/// <summary>
/// 查找类似 Register hotkey failed 的本地化字符串。
/// </summary>
internal static string HotkeyRegFailed {
get {
return ResourceManager.GetString("HotkeyRegFailed", resourceCulture);
}
}
/// <summary>
/// 查找类似 is not the correct client configuration file, please check 的本地化字符串。
/// </summary>

View file

@ -177,6 +177,12 @@
<data name="FillUUID" xml:space="preserve">
<value>Please fill in the user ID</value>
</data>
<data name="HotkeyParseFailed" xml:space="preserve">
<value>Cannot parse hotkey: {0}</value>
</data>
<data name="HotkeyRegFailed" xml:space="preserve">
<value>Register hotkey failed</value>
</data>
<data name="IncorrectClientConfiguration" xml:space="preserve">
<value> is not the correct client configuration file, please check</value>
</data>

View file

@ -177,6 +177,12 @@
<data name="FillUUID" xml:space="preserve">
<value>请填写用户ID</value>
</data>
<data name="HotkeyParseFailed" xml:space="preserve">
<value>无法识别的快捷键: {0}</value>
</data>
<data name="HotkeyRegFailed" xml:space="preserve">
<value>注册快捷键失败,请检查冲突或修改快捷键重试</value>
</data>
<data name="IncorrectClientConfiguration" xml:space="preserve">
<value>不是正确的客户端配置文件,请检查</value>
</data>

View file

@ -112,6 +112,12 @@
<Compile Include="Forms\MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Forms\QuicklyAddUserPACForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\QuicklyAddUserPACForm.Designer.cs">
<DependentUpon>QuicklyAddUserPACForm.cs</DependentUpon>
</Compile>
<Compile Include="Forms\SubSettingForm.cs">
<SubType>Form</SubType>
</Compile>
@ -142,6 +148,8 @@
<Compile Include="Forms\SubSettingControl.Designer.cs">
<DependentUpon>SubSettingControl.cs</DependentUpon>
</Compile>
<Compile Include="Handler\Hotkey\HotkeyCallbacks.cs" />
<Compile Include="Handler\Hotkey\Hotkeys.cs" />
<Compile Include="Handler\MainFormHandler.cs" />
<Compile Include="Handler\SpeedtestHandler.cs" />
<Compile Include="Handler\StatisticsHandler.cs" />
@ -208,6 +216,7 @@
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Tool\FileManager.cs" />
<Compile Include="Handler\Hotkey\HotkeyReg.cs" />
<Compile Include="Tool\Job.cs" />
<Compile Include="Tool\QueryableExtension.cs" />
<Compile Include="Tool\UIRes.cs" />
@ -244,11 +253,18 @@
</EmbeddedResource>
<EmbeddedResource Include="Forms\OptionSettingForm.zh-Hans.resx">
<DependentUpon>OptionSettingForm.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Forms\QRCodeControl.zh-Hans.resx">
<DependentUpon>QRCodeControl.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Forms\QuicklyAddUserPACForm.resx">
<DependentUpon>QuicklyAddUserPACForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\QuicklyAddUserPACForm.zh-Hans.resx">
<DependentUpon>QuicklyAddUserPACForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\SubSettingControl.resx">
<DependentUpon>SubSettingControl.cs</DependentUpon>
<SubType>Designer</SubType>
@ -382,6 +398,9 @@
<Content Include="Resources\privoxy_conf.txt" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="GlobalHotKey">
<Version>1.1.0</Version>
</PackageReference>
<PackageReference Include="Google.Protobuf">
<Version>3.11.4</Version>
</PackageReference>