Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7de149fd7 | ||
|
|
ae38be36f5 | ||
|
|
a20e989211 | ||
|
|
579f47ba0d | ||
|
|
24cad87954 | ||
|
|
84d72cd110 | ||
|
|
c0cd46a5aa | ||
|
|
98613c43ca | ||
|
|
555960e210 | ||
|
|
a18ae5582b | ||
|
|
6d6894591c | ||
|
|
984b97fc14 | ||
|
|
a7f35d4495 | ||
|
|
add92cfa7c | ||
|
|
6079e76be5 | ||
|
|
166c7cb2f5 | ||
|
|
dbd3ca44c2 | ||
|
|
ae495dde54 | ||
|
|
4ae25b2f34 | ||
|
|
cdfb621c59 | ||
|
|
29e8df7d2e | ||
|
|
72ff947d95 | ||
|
|
3edaac5739 | ||
|
|
5777a97119 | ||
|
|
aeddbc1dcc | ||
|
|
2f3e409487 | ||
|
|
aa133bb50b | ||
|
|
3bc79a4ba1 |
7
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
7
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
@@ -3,6 +3,13 @@ description: 在提出问题前请先自行排除服务器端问题和升级到
|
|||||||
title: "[Bug]: "
|
title: "[Bug]: "
|
||||||
labels: ["bug"]
|
labels: ["bug"]
|
||||||
body:
|
body:
|
||||||
|
- type: input
|
||||||
|
id: "os-version"
|
||||||
|
attributes:
|
||||||
|
label: "操作系统和版本"
|
||||||
|
description: "操作系统和版本"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
id: "expectation"
|
id: "expectation"
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
10
.github/workflows/build-linux.yml
vendored
10
.github/workflows/build-linux.yml
vendored
@@ -27,6 +27,9 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.2.2
|
uses: actions/checkout@v4.2.2
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
fetch-depth: '0'
|
||||||
|
|
||||||
- name: Setup
|
- name: Setup
|
||||||
uses: actions/setup-dotnet@v4.3.0
|
uses: actions/setup-dotnet@v4.3.0
|
||||||
@@ -42,7 +45,7 @@ jobs:
|
|||||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4.6.0
|
uses: actions/upload-artifact@v4.6.1
|
||||||
with:
|
with:
|
||||||
name: v2rayN-linux
|
name: v2rayN-linux
|
||||||
path: |
|
path: |
|
||||||
@@ -68,9 +71,8 @@ jobs:
|
|||||||
- name: Package AppImage
|
- name: Package AppImage
|
||||||
if: github.event.inputs.release_tag != ''
|
if: github.event.inputs.release_tag != ''
|
||||||
run: |
|
run: |
|
||||||
chmod 755 package-appimage.sh
|
chmod a+x package-appimage.sh
|
||||||
./package-appimage.sh $OutputArch $OutputPath64 ${{ github.event.inputs.release_tag }}
|
./package-appimage.sh
|
||||||
./package-appimage.sh $OutputArchArm $OutputPathArm64 ${{ github.event.inputs.release_tag }}
|
|
||||||
|
|
||||||
- name: Upload AppImage to release
|
- name: Upload AppImage to release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
|||||||
5
.github/workflows/build-osx.yml
vendored
5
.github/workflows/build-osx.yml
vendored
@@ -27,6 +27,9 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.2.2
|
uses: actions/checkout@v4.2.2
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
fetch-depth: '0'
|
||||||
|
|
||||||
- name: Setup
|
- name: Setup
|
||||||
uses: actions/setup-dotnet@v4.3.0
|
uses: actions/setup-dotnet@v4.3.0
|
||||||
@@ -42,7 +45,7 @@ jobs:
|
|||||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4.6.0
|
uses: actions/upload-artifact@v4.6.1
|
||||||
with:
|
with:
|
||||||
name: v2rayN-macos
|
name: v2rayN-macos
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
5
.github/workflows/build-windows-desktop.yml
vendored
5
.github/workflows/build-windows-desktop.yml
vendored
@@ -27,6 +27,9 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.2.2
|
uses: actions/checkout@v4.2.2
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
fetch-depth: '0'
|
||||||
|
|
||||||
- name: Setup
|
- name: Setup
|
||||||
uses: actions/setup-dotnet@v4.3.0
|
uses: actions/setup-dotnet@v4.3.0
|
||||||
@@ -42,7 +45,7 @@ jobs:
|
|||||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4.6.0
|
uses: actions/upload-artifact@v4.6.1
|
||||||
with:
|
with:
|
||||||
name: v2rayN-windows-desktop
|
name: v2rayN-windows-desktop
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
2
.github/workflows/build-windows.yml
vendored
2
.github/workflows/build-windows.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
|||||||
|
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4.6.0
|
uses: actions/upload-artifact@v4.6.1
|
||||||
with:
|
with:
|
||||||
name: v2rayN-windows
|
name: v2rayN-windows
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "v2rayN/GlobalHotKeys"]
|
||||||
|
path = v2rayN/GlobalHotKeys
|
||||||
|
url = https://github.com/2dust/GlobalHotKeys
|
||||||
@@ -1,71 +1,14 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
Arch="$1"
|
sudo apt update -y
|
||||||
OutputPath="$2"
|
|
||||||
Version="$3"
|
|
||||||
|
|
||||||
FileName="v2rayN-${Arch}.zip"
|
|
||||||
wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName"
|
|
||||||
7z x $FileName -aoa
|
|
||||||
cp -rf v2rayN-${Arch}/* $OutputPath
|
|
||||||
|
|
||||||
PackagePath="v2rayN-Package-${Arch}"
|
|
||||||
mkdir -p "${PackagePath}/AppDir/opt"
|
|
||||||
cp -rf $OutputPath "${PackagePath}/AppDir/opt/v2rayN"
|
|
||||||
echo "When this file exists, app will not store configs under this folder" >"${PackagePath}/AppDir/opt/v2rayN/NotStoreConfigHere.txt"
|
|
||||||
|
|
||||||
if [ $Arch = "linux-64" ]; then
|
|
||||||
Arch2="x86_64"
|
|
||||||
Arch3="amd64"
|
|
||||||
else
|
|
||||||
Arch2="aarch64"
|
|
||||||
Arch3="arm64"
|
|
||||||
fi
|
|
||||||
echo $Arch2
|
|
||||||
|
|
||||||
# basic
|
|
||||||
cat >"${PackagePath}/AppDir/AppRun" <<-EOF
|
|
||||||
#!/bin/sh
|
|
||||||
HERE="\$(dirname "\$(readlink -f "\${0}")")"
|
|
||||||
export PATH="\${HERE}"/opt/v2rayN/:"\${PATH}"
|
|
||||||
export LD_LIBRARY_PATH="\${HERE}"/opt/v2rayN/:"\${LD_LIBRARY_PATH}"
|
|
||||||
exec "\${HERE}/opt/v2rayN/v2rayN" \$@
|
|
||||||
EOF
|
|
||||||
|
|
||||||
cat >"${PackagePath}/AppDir/v2rayN.desktop" <<-EOF
|
|
||||||
[Desktop Entry]
|
|
||||||
Name=v2rayN
|
|
||||||
Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
|
||||||
Exec=v2rayN
|
|
||||||
Icon=v2rayN
|
|
||||||
Terminal=false
|
|
||||||
Type=Application
|
|
||||||
Categories=Network;
|
|
||||||
EOF
|
|
||||||
|
|
||||||
sudo cp "${PackagePath}/AppDir/opt/v2rayN/v2rayN.png" "${PackagePath}/AppDir/v2rayN.png"
|
|
||||||
sudo dpkg --add-architecture ${Arch3}
|
|
||||||
mkdir deb_folder
|
|
||||||
cd deb_folder
|
|
||||||
apt download libicu74:${Arch3}
|
|
||||||
apt download libfontconfig1:${Arch3} || true
|
|
||||||
apt download libfontconfig:${Arch3} || true
|
|
||||||
mkdir ../output_folder
|
|
||||||
for deb in *.deb; do
|
|
||||||
dpkg-deb -x "$deb" ../output_folder/
|
|
||||||
done
|
|
||||||
cd ..
|
|
||||||
find output_folder -type f -name "*.so*" -exec cp {} ${PackagePath}/AppDir/opt/v2rayN/ \;
|
|
||||||
find output_folder -type l -name "*.so*" -exec cp {} ${PackagePath}/AppDir/opt/v2rayN/ \;
|
|
||||||
rm -rf deb_folder output_folder
|
|
||||||
|
|
||||||
sudo chmod 0755 "${PackagePath}/AppDir/opt/v2rayN/v2rayN"
|
|
||||||
sudo chmod 0755 "${PackagePath}/AppDir/AppRun"
|
|
||||||
|
|
||||||
# desktop && PATH
|
|
||||||
|
|
||||||
wget "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
|
||||||
chmod a+x appimagetool-x86_64.AppImage
|
|
||||||
sudo apt install -y libfuse2
|
sudo apt install -y libfuse2
|
||||||
sudo ./appimagetool-x86_64.AppImage "${PackagePath}/AppDir"
|
wget -O pkg2appimage https://github.com/AppImageCommunity/pkg2appimage/releases/download/continuous/pkg2appimage-1eceb30-x86_64.AppImage
|
||||||
sudo mv "v2rayN-${Arch2}.AppImage" "v2rayN-${Arch}.AppImage"
|
chmod a+x pkg2appimage
|
||||||
|
export AppImageOutputArch=$OutputArch
|
||||||
|
export OutputPath=$OutputPath64
|
||||||
|
./pkg2appimage ./pkg2appimage.yml
|
||||||
|
mv out/*.AppImage v2rayN-${AppImageOutputArch}.AppImage
|
||||||
|
export AppImageOutputArch=$OutputArchArm
|
||||||
|
export OutputPath=$OutputPathArm64
|
||||||
|
./pkg2appimage ./pkg2appimage.yml
|
||||||
|
mv out/*.AppImage v2rayN-${AppImageOutputArch}.AppImage
|
||||||
|
|||||||
37
pkg2appimage.yml
Normal file
37
pkg2appimage.yml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
app: v2rayN
|
||||||
|
binpatch: true
|
||||||
|
|
||||||
|
ingredients:
|
||||||
|
script:
|
||||||
|
- export FileName="v2rayN-${AppImageOutputArch}.zip"
|
||||||
|
- wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/${FileName}"
|
||||||
|
- 7z x $FileName -aoa
|
||||||
|
- cp -rf v2rayN-${AppImageOutputArch}/* $OutputPath
|
||||||
|
|
||||||
|
script:
|
||||||
|
- mkdir -p usr/bin usr/lib
|
||||||
|
- cp -rf $OutputPath usr/lib/v2rayN
|
||||||
|
- echo "When this file exists, app will not store configs under this folder" > usr/lib/v2rayN/NotStoreConfigHere.txt
|
||||||
|
- ln -sf usr/lib/v2rayN/v2rayN usr/bin/v2rayN
|
||||||
|
- chmod a+x usr/lib/v2rayN/v2rayN
|
||||||
|
- find usr -type f -exec sh -c 'file "{}" | grep -qi "executable" && chmod +x "{}"' \;
|
||||||
|
- install -Dm644 usr/lib/v2rayN/v2rayN.png v2rayN.png
|
||||||
|
- install -Dm644 usr/lib/v2rayN/v2rayN.png usr/share/pixmaps/v2rayN.png
|
||||||
|
- cat > v2rayN.desktop <<EOF
|
||||||
|
- [Desktop Entry]
|
||||||
|
- Name=v2rayN
|
||||||
|
- Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||||
|
- Exec=v2rayN
|
||||||
|
- Icon=v2rayN
|
||||||
|
- Terminal=false
|
||||||
|
- Type=Application
|
||||||
|
- Categories=Network;
|
||||||
|
- EOF
|
||||||
|
- install -Dm644 v2rayN.desktop usr/share/applications/v2rayN.desktop
|
||||||
|
- cat > AppRun <<\EOF
|
||||||
|
- #!/bin/sh
|
||||||
|
- HERE="$(dirname "$(readlink -f "${0}")")"
|
||||||
|
- cd ${HERE}/usr/lib/v2rayN
|
||||||
|
- exec ${HERE}/usr/lib/v2rayN/v2rayN $@
|
||||||
|
- EOF
|
||||||
|
- chmod a+x AppRun
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.9.3</Version>
|
<Version>7.10.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.2.4" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.2.4" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.4" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.4" />
|
||||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.4" />
|
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.4" />
|
||||||
<PackageVersion Include="CliWrap" Version="3.8.0" />
|
<PackageVersion Include="CliWrap" Version="3.8.1" />
|
||||||
<PackageVersion Include="Downloader" Version="3.3.3" />
|
<PackageVersion Include="Downloader" Version="3.3.3" />
|
||||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.2.0" />
|
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.2.0" />
|
||||||
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
|
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
|
||||||
@@ -22,9 +22,9 @@
|
|||||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.4" />
|
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.4" />
|
||||||
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
|
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
|
||||||
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
||||||
<PackageVersion Include="TaskScheduler" Version="2.11.0" />
|
<PackageVersion Include="TaskScheduler" Version="2.12.0" />
|
||||||
<PackageVersion Include="WebDav.Client" Version="2.8.0" />
|
<PackageVersion Include="WebDav.Client" Version="2.8.0" />
|
||||||
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
|
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
|
||||||
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
|
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
1
v2rayN/GlobalHotKeys
Submodule
1
v2rayN/GlobalHotKeys
Submodule
Submodule v2rayN/GlobalHotKeys added at 35901e2eaa
@@ -20,9 +20,13 @@ public static class ProcUtils
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (fileName.Contains(' '))
|
if (fileName.Contains(' '))
|
||||||
|
{
|
||||||
fileName = fileName.AppendQuotes();
|
fileName = fileName.AppendQuotes();
|
||||||
|
}
|
||||||
if (arguments.Contains(' '))
|
if (arguments.Contains(' '))
|
||||||
|
{
|
||||||
arguments = arguments.AppendQuotes();
|
arguments = arguments.AppendQuotes();
|
||||||
|
}
|
||||||
|
|
||||||
Process proc = new()
|
Process proc = new()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -857,7 +857,7 @@ namespace ServiceLib.Common
|
|||||||
private static async Task<string?> GetLinuxUserId()
|
private static async Task<string?> GetLinuxUserId()
|
||||||
{
|
{
|
||||||
var arg = new List<string>() { "-c", "id -u" };
|
var arg = new List<string>() { "-c", "id -u" };
|
||||||
return await GetCliWrapOutput("/bin/bash", arg);
|
return await GetCliWrapOutput(Global.LinuxBash, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<string?> SetLinuxChmod(string? fileName)
|
public static async Task<string?> SetLinuxChmod(string? fileName)
|
||||||
@@ -868,14 +868,14 @@ namespace ServiceLib.Common
|
|||||||
fileName = fileName.AppendQuotes();
|
fileName = fileName.AppendQuotes();
|
||||||
//File.SetUnixFileMode(fileName, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute);
|
//File.SetUnixFileMode(fileName, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute);
|
||||||
var arg = new List<string>() { "-c", $"chmod +x {fileName}" };
|
var arg = new List<string>() { "-c", $"chmod +x {fileName}" };
|
||||||
return await GetCliWrapOutput("/bin/bash", arg);
|
return await GetCliWrapOutput(Global.LinuxBash, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<string?> GetLinuxFontFamily(string lang)
|
public static async Task<string?> GetLinuxFontFamily(string lang)
|
||||||
{
|
{
|
||||||
// var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" };
|
// var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" };
|
||||||
var arg = new List<string>() { "-c", $"fc-list : family" };
|
var arg = new List<string>() { "-c", $"fc-list : family" };
|
||||||
return await GetCliWrapOutput("/bin/bash", arg);
|
return await GetCliWrapOutput(Global.LinuxBash, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string? GetHomePath()
|
public static string? GetHomePath()
|
||||||
@@ -885,12 +885,6 @@ namespace ServiceLib.Common
|
|||||||
: Environment.GetEnvironmentVariable("HOME");
|
: Environment.GetEnvironmentVariable("HOME");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<string?> GetListNetworkServices()
|
|
||||||
{
|
|
||||||
var arg = new List<string>() { "-c", $"networksetup -listallnetworkservices" };
|
|
||||||
return await GetCliWrapOutput("/bin/bash", arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Platform
|
#endregion Platform
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ namespace ServiceLib
|
|||||||
public const string ClashTunYaml = NamespaceSample + "clash_tun_yaml";
|
public const string ClashTunYaml = NamespaceSample + "clash_tun_yaml";
|
||||||
public const string LinuxAutostartConfig = NamespaceSample + "linux_autostart_config";
|
public const string LinuxAutostartConfig = NamespaceSample + "linux_autostart_config";
|
||||||
public const string PacFileName = NamespaceSample + "pac";
|
public const string PacFileName = NamespaceSample + "pac";
|
||||||
|
public const string ProxySetOSXShellFileName = NamespaceSample + "proxy_set_osx_sh";
|
||||||
|
public const string ProxySetLinuxShellFileName = NamespaceSample + "proxy_set_linux_sh";
|
||||||
|
|
||||||
public const string DefaultSecurity = "auto";
|
public const string DefaultSecurity = "auto";
|
||||||
public const string DefaultNetwork = "tcp";
|
public const string DefaultNetwork = "tcp";
|
||||||
@@ -67,10 +69,11 @@ namespace ServiceLib
|
|||||||
public const int MinFontSize = 8;
|
public const int MinFontSize = 8;
|
||||||
public const string RebootAs = "rebootas";
|
public const string RebootAs = "rebootas";
|
||||||
public const string AvaAssets = "avares://v2rayN/Assets/";
|
public const string AvaAssets = "avares://v2rayN/Assets/";
|
||||||
public const string LocalAppData = "V2RAYN_LOCAL_APPLICATION_DATA";
|
public const string LocalAppData = "V2RAYN_LOCAL_APPLICATION_DATA_V2";
|
||||||
public const string V2RayLocalAsset = "V2RAY_LOCATION_ASSET";
|
public const string V2RayLocalAsset = "V2RAY_LOCATION_ASSET";
|
||||||
public const string XrayLocalAsset = "XRAY_LOCATION_ASSET";
|
public const string XrayLocalAsset = "XRAY_LOCATION_ASSET";
|
||||||
public const int SpeedTestPageSize = 1000;
|
public const int SpeedTestPageSize = 1000;
|
||||||
|
public const string LinuxBash = "/bin/bash";
|
||||||
|
|
||||||
public static readonly List<string> IEProxyProtocols =
|
public static readonly List<string> IEProxyProtocols =
|
||||||
[
|
[
|
||||||
@@ -426,12 +429,12 @@ namespace ServiceLib
|
|||||||
"fakedns+others"
|
"fakedns+others"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> TunMtus =
|
public static readonly List<int> TunMtus =
|
||||||
[
|
[
|
||||||
"1280",
|
1280,
|
||||||
"1408",
|
1408,
|
||||||
"1500",
|
1500,
|
||||||
"9000"
|
9000
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> TunStacks =
|
public static readonly List<string> TunStacks =
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ namespace ServiceLib.Handler
|
|||||||
if (File.Exists(launchAgentPath))
|
if (File.Exists(launchAgentPath))
|
||||||
{
|
{
|
||||||
var args = new[] { "-c", $"launchctl unload -w \"{launchAgentPath}\"" };
|
var args = new[] { "-c", $"launchctl unload -w \"{launchAgentPath}\"" };
|
||||||
await Utils.GetCliWrapOutput("/bin/bash", args);
|
await Utils.GetCliWrapOutput(Global.LinuxBash, args);
|
||||||
|
|
||||||
File.Delete(launchAgentPath);
|
File.Delete(launchAgentPath);
|
||||||
}
|
}
|
||||||
@@ -197,7 +197,7 @@ namespace ServiceLib.Handler
|
|||||||
await File.WriteAllTextAsync(launchAgentPath, plistContent);
|
await File.WriteAllTextAsync(launchAgentPath, plistContent);
|
||||||
|
|
||||||
var args = new[] { "-c", $"launchctl load -w \"{launchAgentPath}\"" };
|
var args = new[] { "-c", $"launchctl load -w \"{launchAgentPath}\"" };
|
||||||
await Utils.GetCliWrapOutput("/bin/bash", args);
|
await Utils.GetCliWrapOutput(Global.LinuxBash, args);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -158,6 +158,7 @@ namespace ServiceLib.Handler
|
|||||||
Length = "100-200",
|
Length = "100-200",
|
||||||
Interval = "10-20"
|
Interval = "10-20"
|
||||||
};
|
};
|
||||||
|
config.GlobalHotkeys ??= new();
|
||||||
|
|
||||||
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
|
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
@@ -724,7 +725,7 @@ namespace ServiceLib.Handler
|
|||||||
profileItem.Network = string.Empty;
|
profileItem.Network = string.Empty;
|
||||||
if (profileItem.ShortId.IsNullOrEmpty())
|
if (profileItem.ShortId.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.ShortId = Global.TunMtus.FirstOrDefault();
|
profileItem.ShortId = Global.TunMtus.First().ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profileItem.Id.IsNullOrEmpty())
|
if (profileItem.Id.IsNullOrEmpty())
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ namespace ServiceLib.Handler
|
|||||||
StartInfo = new()
|
StartInfo = new()
|
||||||
{
|
{
|
||||||
FileName = fileName,
|
FileName = fileName,
|
||||||
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath) : configPath),
|
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath).AppendQuotes() : configPath),
|
||||||
WorkingDirectory = Utils.GetBinConfigPath(),
|
WorkingDirectory = Utils.GetBinConfigPath(),
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
RedirectStandardOutput = displayLog,
|
RedirectStandardOutput = displayLog,
|
||||||
@@ -380,7 +380,7 @@ namespace ServiceLib.Handler
|
|||||||
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
|
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
|
||||||
{
|
{
|
||||||
//Shell scripts
|
//Shell scripts
|
||||||
var shFilePath = Utils.GetBinPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
|
var shFilePath = Utils.GetBinConfigPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
|
||||||
File.Delete(shFilePath);
|
File.Delete(shFilePath);
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.AppendLine("#!/bin/sh");
|
sb.AppendLine("#!/bin/sh");
|
||||||
|
|||||||
@@ -1,202 +1,33 @@
|
|||||||
namespace ServiceLib.Handler.SysProxy
|
namespace ServiceLib.Handler.SysProxy
|
||||||
{
|
{
|
||||||
public class ProxySettingLinux
|
public class ProxySettingLinux
|
||||||
{
|
{
|
||||||
|
private static readonly string _proxySetFileName = $"{Global.ProxySetLinuxShellFileName.Replace(Global.NamespaceSample, "")}.sh";
|
||||||
|
|
||||||
public static async Task SetProxy(string host, int port, string exceptions)
|
public static async Task SetProxy(string host, int port, string exceptions)
|
||||||
{
|
{
|
||||||
var lstCmd = GetSetCmds(host, port, exceptions);
|
List<string> args = ["manual", host, port.ToString(), exceptions];
|
||||||
|
await ExecCmd(args);
|
||||||
await ExecCmd(lstCmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task UnsetProxy()
|
public static async Task UnsetProxy()
|
||||||
{
|
{
|
||||||
var lstCmd = GetUnsetCmds();
|
List<string> args = ["none"];
|
||||||
|
await ExecCmd(args);
|
||||||
await ExecCmd(lstCmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task ExecCmd(List<CmdItem> lstCmd)
|
private static async Task ExecCmd(List<string> args)
|
||||||
{
|
{
|
||||||
foreach (var cmd in lstCmd)
|
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
|
||||||
|
if (!File.Exists(fileName))
|
||||||
{
|
{
|
||||||
if (cmd is null || cmd.Cmd.IsNullOrEmpty() || cmd.Arguments is null)
|
var contents = EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName);
|
||||||
{
|
await File.AppendAllTextAsync(fileName, contents);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
await Task.Delay(10);
|
|
||||||
await Utils.GetCliWrapOutput(cmd.Cmd, cmd.Arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<CmdItem> GetSetCmds(string host, int port, string exceptions)
|
await Utils.SetLinuxChmod(fileName);
|
||||||
{
|
|
||||||
var isKde = IsKde(out var configDir);
|
|
||||||
List<string> lstType = ["", "http", "https", "socks", "ftp"];
|
|
||||||
List<CmdItem> lstCmd = [];
|
|
||||||
|
|
||||||
//GNOME
|
|
||||||
foreach (var type in lstType)
|
|
||||||
{
|
|
||||||
lstCmd.AddRange(GetSetCmd4Gnome(type, host, port));
|
|
||||||
}
|
|
||||||
if (exceptions.IsNotEmpty())
|
|
||||||
{
|
|
||||||
lstCmd.AddRange(GetSetCmd4Gnome("exceptions", exceptions, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isKde)
|
await Utils.GetCliWrapOutput(fileName, args);
|
||||||
{
|
|
||||||
foreach (var type in lstType)
|
|
||||||
{
|
|
||||||
lstCmd.AddRange(GetSetCmd4Kde(type, host, port, configDir));
|
|
||||||
}
|
|
||||||
if (exceptions.IsNotEmpty())
|
|
||||||
{
|
|
||||||
lstCmd.AddRange(GetSetCmd4Kde("exceptions", exceptions, 0, configDir));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify system to reload
|
|
||||||
lstCmd.Add(new CmdItem()
|
|
||||||
{
|
|
||||||
Cmd = "dbus-send",
|
|
||||||
Arguments = ["--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return lstCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<CmdItem> GetUnsetCmds()
|
|
||||||
{
|
|
||||||
var isKde = IsKde(out var configDir);
|
|
||||||
List<CmdItem> lstCmd = [];
|
|
||||||
|
|
||||||
//GNOME
|
|
||||||
lstCmd.Add(new CmdItem()
|
|
||||||
{
|
|
||||||
Cmd = "gsettings",
|
|
||||||
Arguments = ["set", "org.gnome.system.proxy", "mode", "none"]
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isKde)
|
|
||||||
{
|
|
||||||
lstCmd.Add(new CmdItem()
|
|
||||||
{
|
|
||||||
Cmd = GetKdeVersion(),
|
|
||||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0"]
|
|
||||||
});
|
|
||||||
|
|
||||||
// Notify system to reload
|
|
||||||
lstCmd.Add(new CmdItem()
|
|
||||||
{
|
|
||||||
Cmd = "dbus-send",
|
|
||||||
Arguments = ["--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return lstCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<CmdItem> GetSetCmd4Kde(string type, string host, int port, string configDir)
|
|
||||||
{
|
|
||||||
List<CmdItem> lstCmd = [];
|
|
||||||
var cmd = GetKdeVersion();
|
|
||||||
|
|
||||||
if (type.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
lstCmd.Add(new()
|
|
||||||
{
|
|
||||||
Cmd = cmd,
|
|
||||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (type == "exceptions")
|
|
||||||
{
|
|
||||||
lstCmd.Add(new()
|
|
||||||
{
|
|
||||||
Cmd = cmd,
|
|
||||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "NoProxyFor", host]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var type2 = type.Equals("https") ? "http" : type;
|
|
||||||
lstCmd.Add(new CmdItem()
|
|
||||||
{
|
|
||||||
Cmd = cmd,
|
|
||||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", $"{type}Proxy", $"{type2}://{host}:{port}"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return lstCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<CmdItem> GetSetCmd4Gnome(string type, string host, int port)
|
|
||||||
{
|
|
||||||
List<CmdItem> lstCmd = [];
|
|
||||||
|
|
||||||
if (type.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
lstCmd.Add(new()
|
|
||||||
{
|
|
||||||
Cmd = "gsettings",
|
|
||||||
Arguments = ["set", "org.gnome.system.proxy", "mode", "manual"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (type == "exceptions")
|
|
||||||
{
|
|
||||||
lstCmd.Add(new()
|
|
||||||
{
|
|
||||||
Cmd = "gsettings",
|
|
||||||
Arguments = ["set", $"org.gnome.system.proxy", "ignore-hosts", JsonUtils.Serialize(host.Split(','), false)]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lstCmd.Add(new()
|
|
||||||
{
|
|
||||||
Cmd = "gsettings",
|
|
||||||
Arguments = ["set", $"org.gnome.system.proxy.{type}", "host", host]
|
|
||||||
});
|
|
||||||
|
|
||||||
lstCmd.Add(new()
|
|
||||||
{
|
|
||||||
Cmd = "gsettings",
|
|
||||||
Arguments = ["set", $"org.gnome.system.proxy.{type}", "port", $"{port}"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return lstCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsKde(out string configDir)
|
|
||||||
{
|
|
||||||
configDir = "/home";
|
|
||||||
var desktop = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP");
|
|
||||||
var desktop2 = Environment.GetEnvironmentVariable("XDG_SESSION_DESKTOP");
|
|
||||||
var isKde = string.Equals(desktop, "KDE", StringComparison.OrdinalIgnoreCase)
|
|
||||||
|| string.Equals(desktop, "plasma", StringComparison.OrdinalIgnoreCase)
|
|
||||||
|| string.Equals(desktop2, "KDE", StringComparison.OrdinalIgnoreCase)
|
|
||||||
|| string.Equals(desktop2, "plasma", StringComparison.OrdinalIgnoreCase);
|
|
||||||
if (isKde)
|
|
||||||
{
|
|
||||||
var homeDir = Environment.GetEnvironmentVariable("HOME");
|
|
||||||
if (homeDir != null)
|
|
||||||
{
|
|
||||||
configDir = Path.Combine(homeDir, ".config");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return isKde;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetKdeVersion()
|
|
||||||
{
|
|
||||||
var ver = Environment.GetEnvironmentVariable("KDE_SESSION_VERSION") ?? "0";
|
|
||||||
return ver switch
|
|
||||||
{
|
|
||||||
"6" => "kwriteconfig6",
|
|
||||||
_ => "kwriteconfig5"
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,101 +1,38 @@
|
|||||||
namespace ServiceLib.Handler.SysProxy
|
namespace ServiceLib.Handler.SysProxy
|
||||||
{
|
{
|
||||||
public class ProxySettingOSX
|
public class ProxySettingOSX
|
||||||
{
|
{
|
||||||
/// <summary>
|
private static readonly string _proxySetFileName = $"{Global.ProxySetOSXShellFileName.Replace(Global.NamespaceSample, "")}.sh";
|
||||||
/// 应用接口类型
|
|
||||||
/// </summary>
|
|
||||||
private static readonly List<string> LstInterface = ["Ethernet", "Wi-Fi", "Thunderbolt Bridge", "USB 10/100/1000 LAN"];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 代理类型,对应 http,https,socks
|
|
||||||
/// </summary>
|
|
||||||
private static readonly List<string> LstTypes = ["setwebproxy", "setsecurewebproxy", "setsocksfirewallproxy"];
|
|
||||||
|
|
||||||
public static async Task SetProxy(string host, int port, string exceptions)
|
public static async Task SetProxy(string host, int port, string exceptions)
|
||||||
{
|
{
|
||||||
var lstInterface = await GetListNetworkServices();
|
List<string> args = ["set", host, port.ToString()];
|
||||||
var lstCmd = GetSetCmds(lstInterface, host, port, exceptions);
|
if (exceptions.IsNotEmpty())
|
||||||
await ExecCmd(lstCmd);
|
{
|
||||||
|
args.AddRange(exceptions.Split(','));
|
||||||
|
}
|
||||||
|
|
||||||
|
await ExecCmd(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task UnsetProxy()
|
public static async Task UnsetProxy()
|
||||||
{
|
{
|
||||||
var lstInterface = await GetListNetworkServices();
|
List<string> args = ["clear"];
|
||||||
var lstCmd = GetUnsetCmds(lstInterface);
|
await ExecCmd(args);
|
||||||
await ExecCmd(lstCmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task ExecCmd(List<CmdItem> lstCmd)
|
private static async Task ExecCmd(List<string> args)
|
||||||
{
|
{
|
||||||
foreach (var cmd in lstCmd)
|
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
|
||||||
|
if (!File.Exists(fileName))
|
||||||
{
|
{
|
||||||
if (cmd is null || cmd.Cmd.IsNullOrEmpty() || cmd.Arguments is null)
|
var contents = EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName);
|
||||||
{
|
await File.AppendAllTextAsync(fileName, contents);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(10);
|
await Utils.SetLinuxChmod(fileName);
|
||||||
await Utils.GetCliWrapOutput(cmd.Cmd, cmd.Arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<CmdItem> GetSetCmds(List<string> lstInterface, string host, int port, string exceptions)
|
|
||||||
{
|
|
||||||
List<CmdItem> lstCmd = [];
|
|
||||||
foreach (var interf in lstInterface)
|
|
||||||
{
|
|
||||||
foreach (var type in LstTypes)
|
|
||||||
{
|
|
||||||
lstCmd.Add(new CmdItem()
|
|
||||||
{
|
|
||||||
Cmd = "networksetup",
|
|
||||||
Arguments = [$"-{type}", interf, host, port.ToString()]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (exceptions.IsNotEmpty())
|
|
||||||
{
|
|
||||||
List<string> args = [$"-setproxybypassdomains", interf];
|
|
||||||
args.AddRange(exceptions.Split(','));
|
|
||||||
lstCmd.Add(new CmdItem()
|
|
||||||
{
|
|
||||||
Cmd = "networksetup",
|
|
||||||
Arguments = args
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return lstCmd;
|
await Utils.GetCliWrapOutput(fileName, args);
|
||||||
}
|
|
||||||
|
|
||||||
private static List<CmdItem> GetUnsetCmds(List<string> lstInterface)
|
|
||||||
{
|
|
||||||
List<CmdItem> lstCmd = [];
|
|
||||||
foreach (var interf in lstInterface)
|
|
||||||
{
|
|
||||||
foreach (var type in LstTypes)
|
|
||||||
{
|
|
||||||
lstCmd.Add(new CmdItem()
|
|
||||||
{
|
|
||||||
Cmd = "networksetup",
|
|
||||||
Arguments = [$"-{type}state", interf, "off"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lstCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<List<string>> GetListNetworkServices()
|
|
||||||
{
|
|
||||||
var services = await Utils.GetListNetworkServices();
|
|
||||||
if (services.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
return LstInterface;
|
|
||||||
}
|
|
||||||
|
|
||||||
var lst = services.Split(Environment.NewLine).Where(t => t.Length > 0 && t.Contains('*') == false);
|
|
||||||
return lst.ToList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
118
v2rayN/ServiceLib/Sample/proxy_set_linux_sh
Normal file
118
v2rayN/ServiceLib/Sample/proxy_set_linux_sh
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Function to set proxy for GNOME
|
||||||
|
set_gnome_proxy() {
|
||||||
|
local MODE=$1
|
||||||
|
local PROXY_IP=$2
|
||||||
|
local PROXY_PORT=$3
|
||||||
|
local IGNORE_HOSTS=$4
|
||||||
|
|
||||||
|
# Set the proxy mode
|
||||||
|
gsettings set org.gnome.system.proxy mode "$MODE"
|
||||||
|
|
||||||
|
if [ "$MODE" == "manual" ]; then
|
||||||
|
# List of protocols
|
||||||
|
local PROTOCOLS=("http" "https" "ftp" "socks")
|
||||||
|
|
||||||
|
# Loop through protocols to set the proxy
|
||||||
|
for PROTOCOL in "${PROTOCOLS[@]}"; do
|
||||||
|
gsettings set org.gnome.system.proxy.$PROTOCOL host "$PROXY_IP"
|
||||||
|
gsettings set org.gnome.system.proxy.$PROTOCOL port "$PROXY_PORT"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Set ignored hosts
|
||||||
|
gsettings set org.gnome.system.proxy ignore-hosts "['$IGNORE_HOSTS']"
|
||||||
|
|
||||||
|
echo "GNOME: Manual proxy settings applied."
|
||||||
|
echo "Proxy IP: $PROXY_IP"
|
||||||
|
echo "Proxy Port: $PROXY_PORT"
|
||||||
|
echo "Ignored Hosts: $IGNORE_HOSTS"
|
||||||
|
elif [ "$MODE" == "none" ]; then
|
||||||
|
echo "GNOME: Proxy disabled."
|
||||||
|
else
|
||||||
|
echo "GNOME: Invalid mode. Use 'none' or 'manual'."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to set proxy for KDE
|
||||||
|
set_kde_proxy() {
|
||||||
|
local MODE=$1
|
||||||
|
local PROXY_IP=$2
|
||||||
|
local PROXY_PORT=$3
|
||||||
|
local IGNORE_HOSTS=$4
|
||||||
|
|
||||||
|
# Determine the correct kwriteconfig command based on KDE_SESSION_VERSION
|
||||||
|
if [ "$KDE_SESSION_VERSION" == "6" ]; then
|
||||||
|
KWRITECONFIG="kwriteconfig6"
|
||||||
|
else
|
||||||
|
KWRITECONFIG="kwriteconfig5"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# KDE uses kwriteconfig to modify proxy settings
|
||||||
|
if [ "$MODE" == "manual" ]; then
|
||||||
|
# Set proxy for all protocols
|
||||||
|
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key ProxyType 1
|
||||||
|
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key httpProxy "http://$PROXY_IP:$PROXY_PORT"
|
||||||
|
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key httpsProxy "http://$PROXY_IP:$PROXY_PORT"
|
||||||
|
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key ftpProxy "http://$PROXY_IP:$PROXY_PORT"
|
||||||
|
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key socksProxy "http://$PROXY_IP:$PROXY_PORT"
|
||||||
|
|
||||||
|
# Set ignored hosts
|
||||||
|
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key NoProxyFor "$IGNORE_HOSTS"
|
||||||
|
|
||||||
|
echo "KDE: Manual proxy settings applied."
|
||||||
|
echo "Proxy IP: $PROXY_IP"
|
||||||
|
echo "Proxy Port: $PROXY_PORT"
|
||||||
|
echo "Ignored Hosts: $IGNORE_HOSTS"
|
||||||
|
elif [ "$MODE" == "none" ]; then
|
||||||
|
# Disable proxy
|
||||||
|
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key ProxyType 0
|
||||||
|
echo "KDE: Proxy disabled."
|
||||||
|
else
|
||||||
|
echo "KDE: Invalid mode. Use 'none' or 'manual'."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Apply changes by restarting KDE's network settings
|
||||||
|
dbus-send --type=signal /KIO/Scheduler org.kde.KIO.Scheduler.reparseSlaveConfiguration string:""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detect the current desktop environment
|
||||||
|
detect_desktop_environment() {
|
||||||
|
if [ "$XDG_CURRENT_DESKTOP" == "GNOME" ] || [ "$XDG_CURRENT_DESKTOP" == "ubuntu:GNOME" ] || [ "$XDG_SESSION_DESKTOP" == "GNOME" ] || [ "$XDG_SESSION_DESKTOP" == "ubuntu:GNOME" ]; then
|
||||||
|
echo "gnome"
|
||||||
|
elif [ "$XDG_CURRENT_DESKTOP" == "KDE" ] || [ "$XDG_CURRENT_DESKTOP" == "plasma" ] || [ "$XDG_SESSION_DESKTOP" == "KDE" ] || [ "$XDG_SESSION_DESKTOP" == "plasma" ]; then
|
||||||
|
echo "kde"
|
||||||
|
else
|
||||||
|
echo "unsupported"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main script logic
|
||||||
|
if [ "$#" -lt 1 ]; then
|
||||||
|
echo "Usage: $0 <mode> [proxy_ip proxy_port ignore_hosts]"
|
||||||
|
echo " mode: 'none' or 'manual'"
|
||||||
|
echo " If mode is 'manual', provide proxy IP, port, and ignore hosts."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the mode
|
||||||
|
MODE=$1
|
||||||
|
PROXY_IP=$2
|
||||||
|
PROXY_PORT=$3
|
||||||
|
IGNORE_HOSTS=$4
|
||||||
|
|
||||||
|
# Detect desktop environment
|
||||||
|
DE=$(detect_desktop_environment)
|
||||||
|
|
||||||
|
# Apply settings based on the desktop environment
|
||||||
|
if [ "$DE" == "gnome" ]; then
|
||||||
|
set_gnome_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
||||||
|
elif [ "$DE" == "kde" ]; then
|
||||||
|
set_gnome_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
||||||
|
set_kde_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
||||||
|
else
|
||||||
|
echo "Unsupported desktop environment: $DE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
74
v2rayN/ServiceLib/Sample/proxy_set_osx_sh
Normal file
74
v2rayN/ServiceLib/Sample/proxy_set_osx_sh
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Function to set proxy
|
||||||
|
set_proxy() {
|
||||||
|
PROXY_IP=$1
|
||||||
|
PROXY_PORT=$2
|
||||||
|
|
||||||
|
shift 2
|
||||||
|
BYPASS_DOMAINS=("$@")
|
||||||
|
# If no bypass domains are provided, set it to empty by default
|
||||||
|
if [ ${#BYPASS_DOMAINS[@]} -eq 0 ]; then
|
||||||
|
BYPASS_DOMAINS=("")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get all network service names
|
||||||
|
SERVICES=$(networksetup -listallnetworkservices | grep -v '*')
|
||||||
|
|
||||||
|
# Loop through each network service
|
||||||
|
echo "$SERVICES" | while read -r SERVICE; do
|
||||||
|
echo "Setting proxy for network service '$SERVICE'..."
|
||||||
|
# Set HTTP proxy
|
||||||
|
networksetup -setwebproxy "$SERVICE" "$PROXY_IP" "$PROXY_PORT"
|
||||||
|
|
||||||
|
# Set HTTPS proxy
|
||||||
|
networksetup -setsecurewebproxy "$SERVICE" "$PROXY_IP" "$PROXY_PORT"
|
||||||
|
|
||||||
|
# Set SOCKS proxy
|
||||||
|
networksetup -setsocksfirewallproxy "$SERVICE" "$PROXY_IP" "$PROXY_PORT"
|
||||||
|
|
||||||
|
# Set bypass domains
|
||||||
|
networksetup -setproxybypassdomains "$SERVICE" "${BYPASS_DOMAINS[@]}"
|
||||||
|
echo "Proxy for network service '$SERVICE' has been set to $PROXY_IP:$PROXY_PORT"
|
||||||
|
done
|
||||||
|
echo "Proxy settings for all network services are complete!"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to disable proxy
|
||||||
|
clear_proxy() {
|
||||||
|
# Get all network service names
|
||||||
|
SERVICES=$(networksetup -listallnetworkservices | grep -v '*')
|
||||||
|
|
||||||
|
# Loop through each network service
|
||||||
|
echo "$SERVICES" | while read -r SERVICE; do
|
||||||
|
echo "Disabling proxy and clearing bypass domains for network service '$SERVICE'..."
|
||||||
|
# Disable HTTP proxy
|
||||||
|
networksetup -setwebproxystate "$SERVICE" off
|
||||||
|
|
||||||
|
# Disable HTTPS proxy
|
||||||
|
networksetup -setsecurewebproxystate "$SERVICE" off
|
||||||
|
|
||||||
|
# Disable SOCKS proxy
|
||||||
|
networksetup -setsocksfirewallproxystate "$SERVICE" off
|
||||||
|
|
||||||
|
echo "Proxy for network service '$SERVICE' has been disabled"
|
||||||
|
done
|
||||||
|
echo "Proxy for all network services has been disabled!"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main script logic
|
||||||
|
if [ "$1" == "set" ]; then
|
||||||
|
# Check if enough parameters are passed for setting proxy
|
||||||
|
if [ "$#" -lt 3 ]; then
|
||||||
|
echo "Usage: $0 set <IP Address> <Port> [Bypass Domain 1 Bypass Domain 2 ...]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
set_proxy "$2" "$3" "${@:4}"
|
||||||
|
elif [ "$1" == "clear" ]; then
|
||||||
|
clear_proxy
|
||||||
|
else
|
||||||
|
echo "Usage:"
|
||||||
|
echo " To set proxy: $0 set <IP Address> <Port> [Bypass Domain 1 Bypass Domain 2 ...]"
|
||||||
|
echo " To clear proxy: $0 clear"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -29,6 +29,8 @@
|
|||||||
<EmbeddedResource Include="Sample\dns_singbox_normal" />
|
<EmbeddedResource Include="Sample\dns_singbox_normal" />
|
||||||
<EmbeddedResource Include="Sample\dns_v2ray_normal" />
|
<EmbeddedResource Include="Sample\dns_v2ray_normal" />
|
||||||
<EmbeddedResource Include="Sample\pac" />
|
<EmbeddedResource Include="Sample\pac" />
|
||||||
|
<EmbeddedResource Include="Sample\proxy_set_linux_sh" />
|
||||||
|
<EmbeddedResource Include="Sample\proxy_set_osx_sh" />
|
||||||
<EmbeddedResource Include="Sample\SampleClientConfig" />
|
<EmbeddedResource Include="Sample\SampleClientConfig" />
|
||||||
<EmbeddedResource Include="Sample\SampleHttpRequest" />
|
<EmbeddedResource Include="Sample\SampleHttpRequest" />
|
||||||
<EmbeddedResource Include="Sample\SampleHttpResponse" />
|
<EmbeddedResource Include="Sample\SampleHttpResponse" />
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ namespace ServiceLib.Services.CoreConfig
|
|||||||
//enable tun mode
|
//enable tun mode
|
||||||
if (_config.TunModeItem.EnableTun)
|
if (_config.TunModeItem.EnableTun)
|
||||||
{
|
{
|
||||||
string tun = EmbedUtils.GetEmbedText(Global.ClashTunYaml);
|
var tun = EmbedUtils.GetEmbedText(Global.ClashTunYaml);
|
||||||
if (Utils.IsNotEmpty(tun))
|
if (Utils.IsNotEmpty(tun))
|
||||||
{
|
{
|
||||||
var tunContent = YamlUtils.FromYaml<Dictionary<string, object>>(tun);
|
var tunContent = YamlUtils.FromYaml<Dictionary<string, object>>(tun);
|
||||||
|
|||||||
@@ -599,7 +599,7 @@ namespace ServiceLib.Services.CoreConfig
|
|||||||
{
|
{
|
||||||
if (_config.TunModeItem.Mtu <= 0)
|
if (_config.TunModeItem.Mtu <= 0)
|
||||||
{
|
{
|
||||||
_config.TunModeItem.Mtu = Utils.ToInt(Global.TunMtus.First());
|
_config.TunModeItem.Mtu = Global.TunMtus.First();
|
||||||
}
|
}
|
||||||
if (Utils.IsNullOrEmpty(_config.TunModeItem.Stack))
|
if (Utils.IsNullOrEmpty(_config.TunModeItem.Stack))
|
||||||
{
|
{
|
||||||
@@ -745,7 +745,7 @@ namespace ServiceLib.Services.CoreConfig
|
|||||||
outbound.peer_public_key = node.PublicKey;
|
outbound.peer_public_key = node.PublicKey;
|
||||||
outbound.reserved = Utils.String2List(node.Path)?.Select(int.Parse).ToList();
|
outbound.reserved = Utils.String2List(node.Path)?.Select(int.Parse).ToList();
|
||||||
outbound.local_address = Utils.String2List(node.RequestHost);
|
outbound.local_address = Utils.String2List(node.RequestHost);
|
||||||
outbound.mtu = Utils.ToInt(node.ShortId.IsNullOrEmpty() ? Global.TunMtus.FirstOrDefault() : node.ShortId);
|
outbound.mtu = Utils.ToInt(node.ShortId.IsNullOrEmpty() ? Global.TunMtus.First() : node.ShortId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
@@ -222,20 +222,20 @@ namespace ServiceLib.Services
|
|||||||
|
|
||||||
public async Task<int> RunAvailabilityCheck(IWebProxy? webProxy)
|
public async Task<int> RunAvailabilityCheck(IWebProxy? webProxy)
|
||||||
{
|
{
|
||||||
|
var responseTime = -1;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
webProxy ??= await GetWebProxy(true);
|
webProxy ??= await GetWebProxy(true);
|
||||||
|
var config = AppHandler.Instance.Config;
|
||||||
|
|
||||||
try
|
for (var i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
var config = AppHandler.Instance.Config;
|
responseTime = await GetRealPingTime(config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
|
||||||
var responseTime = await GetRealPingTime(config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
|
if (responseTime > 0)
|
||||||
return responseTime;
|
{
|
||||||
}
|
break;
|
||||||
catch (Exception ex)
|
}
|
||||||
{
|
await Task.Delay(500);
|
||||||
Logging.SaveLog(_tag, ex);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -243,6 +243,7 @@ namespace ServiceLib.Services
|
|||||||
Logging.SaveLog(_tag, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
return responseTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> GetRealPingTime(string url, IWebProxy? webProxy, int downloadTimeout)
|
public async Task<int> GetRealPingTime(string url, IWebProxy? webProxy, int downloadTimeout)
|
||||||
@@ -319,4 +320,4 @@ namespace ServiceLib.Services
|
|||||||
ServicePointManager.DefaultConnectionLimit = 256;
|
ServicePointManager.DefaultConnectionLimit = 256;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -336,21 +336,19 @@ namespace ServiceLib.Services
|
|||||||
ipAddress = ipHostInfo.AddressList.First();
|
ipAddress = ipHostInfo.AddressList.First();
|
||||||
}
|
}
|
||||||
|
|
||||||
var timer = Stopwatch.StartNew();
|
|
||||||
|
|
||||||
IPEndPoint endPoint = new(ipAddress, port);
|
IPEndPoint endPoint = new(ipAddress, port);
|
||||||
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||||
|
|
||||||
|
var timer = Stopwatch.StartNew();
|
||||||
var result = clientSocket.BeginConnect(endPoint, null, null);
|
var result = clientSocket.BeginConnect(endPoint, null, null);
|
||||||
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
|
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
|
||||||
{
|
{
|
||||||
throw new TimeoutException("connect timeout (5s): " + url);
|
throw new TimeoutException("connect timeout (5s): " + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
clientSocket.EndConnect(result);
|
|
||||||
|
|
||||||
timer.Stop();
|
timer.Stop();
|
||||||
responseTime = (int)timer.Elapsed.TotalMilliseconds;
|
responseTime = (int)timer.Elapsed.TotalMilliseconds;
|
||||||
|
|
||||||
|
clientSocket.EndConnect(result);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
65
v2rayN/ServiceLib/ViewModels/GlobalHotkeySettingViewModel.cs
Normal file
65
v2rayN/ServiceLib/ViewModels/GlobalHotkeySettingViewModel.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
using System.Reactive;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace ServiceLib.ViewModels
|
||||||
|
{
|
||||||
|
public class GlobalHotkeySettingViewModel : MyReactiveObject
|
||||||
|
{
|
||||||
|
private readonly List<KeyEventItem> _globalHotkeys;
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
|
||||||
|
|
||||||
|
public GlobalHotkeySettingViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
|
||||||
|
{
|
||||||
|
_config = AppHandler.Instance.Config;
|
||||||
|
_updateView = updateView;
|
||||||
|
|
||||||
|
_globalHotkeys = JsonUtils.DeepCopy(_config.GlobalHotkeys);
|
||||||
|
|
||||||
|
SaveCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||||
|
{
|
||||||
|
await SaveSettingAsync();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyEventItem GetKeyEventItem(EGlobalHotkey eg)
|
||||||
|
{
|
||||||
|
var item = _globalHotkeys.FirstOrDefault((it) => it.EGlobalHotkey == eg);
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
item = new()
|
||||||
|
{
|
||||||
|
EGlobalHotkey = eg,
|
||||||
|
Control = false,
|
||||||
|
Alt = false,
|
||||||
|
Shift = false,
|
||||||
|
KeyCode = null
|
||||||
|
};
|
||||||
|
_globalHotkeys.Add(item);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetKeyEventItem()
|
||||||
|
{
|
||||||
|
_globalHotkeys.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveSettingAsync()
|
||||||
|
{
|
||||||
|
_config.GlobalHotkeys = _globalHotkeys;
|
||||||
|
|
||||||
|
if (await ConfigHandler.SaveConfig(_config) == 0)
|
||||||
|
{
|
||||||
|
_updateView?.Invoke(EViewAction.CloseWindow, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NoticeHandler.Instance.Enqueue(ResUI.OperationFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -316,6 +316,8 @@ namespace ServiceLib.ViewModels
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, ResUI.Speedtesting);
|
||||||
|
|
||||||
var msg = await (new UpdateService()).RunAvailabilityCheck();
|
var msg = await (new UpdateService()).RunAvailabilityCheck();
|
||||||
|
|
||||||
NoticeHandler.Instance.SendMessageEx(msg);
|
NoticeHandler.Instance.SendMessageEx(msg);
|
||||||
|
|||||||
91
v2rayN/v2rayN.Desktop/Handler/HotkeyHandler.cs
Normal file
91
v2rayN/v2rayN.Desktop/Handler/HotkeyHandler.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
using System.Reactive.Linq;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
using Avalonia.Win32.Input;
|
||||||
|
using GlobalHotKeys;
|
||||||
|
|
||||||
|
namespace v2rayN.Desktop.Handler
|
||||||
|
{
|
||||||
|
public sealed class HotkeyHandler
|
||||||
|
{
|
||||||
|
private static readonly Lazy<HotkeyHandler> _instance = new(() => new());
|
||||||
|
public static HotkeyHandler Instance = _instance.Value;
|
||||||
|
private readonly Dictionary<int, EGlobalHotkey> _hotkeyTriggerDic = new();
|
||||||
|
private HotKeyManager? _hotKeyManager;
|
||||||
|
|
||||||
|
private Config? _config;
|
||||||
|
|
||||||
|
private event Action<EGlobalHotkey>? _updateFunc;
|
||||||
|
|
||||||
|
public bool IsPause { get; set; } = false;
|
||||||
|
|
||||||
|
public void Init(Config config, Action<EGlobalHotkey> updateFunc)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_updateFunc = updateFunc;
|
||||||
|
|
||||||
|
Register();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_hotKeyManager?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Register()
|
||||||
|
{
|
||||||
|
if (_config.GlobalHotkeys.Any(t => t.KeyCode > 0) == false)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_hotKeyManager ??= new GlobalHotKeys.HotKeyManager();
|
||||||
|
_hotkeyTriggerDic.Clear();
|
||||||
|
|
||||||
|
foreach (var item in _config.GlobalHotkeys)
|
||||||
|
{
|
||||||
|
if (item.KeyCode is null or 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vKey = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode);
|
||||||
|
var modifiers = Modifiers.NoRepeat;
|
||||||
|
if (item.Control)
|
||||||
|
{
|
||||||
|
modifiers |= Modifiers.Control;
|
||||||
|
}
|
||||||
|
if (item.Shift)
|
||||||
|
{
|
||||||
|
modifiers |= Modifiers.Shift;
|
||||||
|
}
|
||||||
|
if (item.Alt)
|
||||||
|
{
|
||||||
|
modifiers |= Modifiers.Alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = _hotKeyManager?.Register((VirtualKeyCode)vKey, modifiers);
|
||||||
|
if (result?.IsSuccessful == true)
|
||||||
|
{
|
||||||
|
_hotkeyTriggerDic.Add(result.Id, item.EGlobalHotkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_hotKeyManager?.HotKeyPressed
|
||||||
|
.ObserveOn(AvaloniaScheduler.Instance)
|
||||||
|
.Subscribe(OnNext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnNext(HotKey key)
|
||||||
|
{
|
||||||
|
if (_updateFunc == null || IsPause)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_hotkeyTriggerDic.TryGetValue(key.Id, out var value))
|
||||||
|
{
|
||||||
|
_updateFunc?.Invoke(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||||
Title="v2rayN"
|
Title="{x:Static resx:ResUI.menuAddCustomServer}"
|
||||||
Width="700"
|
Width="700"
|
||||||
Height="500"
|
Height="500"
|
||||||
x:DataType="vms:AddServer2ViewModel"
|
x:DataType="vms:AddServer2ViewModel"
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<DockPanel Margin="{StaticResource Margin8}">
|
<DockPanel Margin="{StaticResource Margin8}">
|
||||||
<StackPanel
|
<StackPanel
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
DockPanel.Dock="Bottom"
|
DockPanel.Dock="Bottom"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<Button
|
<Button
|
||||||
@@ -45,8 +45,8 @@
|
|||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbRemarks}" />
|
Text="{x:Static resx:ResUI.TbRemarks}" />
|
||||||
|
|
||||||
<TextBox
|
<TextBox
|
||||||
@@ -54,24 +54,24 @@
|
|||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="400"
|
Width="400"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center" />
|
||||||
Margin="{StaticResource Margin4}" />
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbAddress}" />
|
Text="{x:Static resx:ResUI.TbAddress}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtAddress"
|
x:Name="txtAddress"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="400"
|
Width="400"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
IsReadOnly="True" />
|
IsReadOnly="True" />
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
@@ -91,23 +91,23 @@
|
|||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbCoreType}" />
|
Text="{x:Static resx:ResUI.TbCoreType}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbCoreType"
|
x:Name="cmbCoreType"
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
MaxDropDownHeight="1000" />
|
MaxDropDownHeight="1000" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbDisplayLog}" />
|
Text="{x:Static resx:ResUI.TbDisplayLog}" />
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
@@ -116,27 +116,27 @@
|
|||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
x:Name="togDisplayLog"
|
x:Name="togDisplayLog"
|
||||||
HorizontalAlignment="Left"
|
Margin="{StaticResource Margin4}"
|
||||||
Margin="{StaticResource Margin4}" />
|
HorizontalAlignment="Left" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource MarginLr8}"
|
Margin="{StaticResource MarginLr8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TipDisplayLog}" />
|
Text="{x:Static resx:ResUI.TipDisplayLog}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="5"
|
Grid.Row="5"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbPreSocksPort}" />
|
Text="{x:Static resx:ResUI.TbPreSocksPort}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtPreSocksPort"
|
x:Name="txtPreSocksPort"
|
||||||
Grid.Row="5"
|
Grid.Row="5"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
HorizontalAlignment="Left"
|
Margin="{StaticResource Margin4}"
|
||||||
Margin="{StaticResource Margin4}" />
|
HorizontalAlignment="Left" />
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Row="6"
|
Grid.Row="6"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
@@ -149,8 +149,8 @@
|
|||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Width="500"
|
Width="500"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource MarginLr8}"
|
Margin="{StaticResource MarginLr8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.CustomServerTips}"
|
Text="{x:Static resx:ResUI.CustomServerTips}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -6,17 +6,17 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||||
Title="{x:Static resx:ResUI.menuSetting}"
|
Title="{x:Static resx:ResUI.menuGlobalHotkeySetting}"
|
||||||
Width="700"
|
Width="700"
|
||||||
Height="500"
|
Height="500"
|
||||||
x:DataType="vms:SubEditViewModel"
|
x:DataType="vms:GlobalHotkeySettingViewModel"
|
||||||
ShowInTaskbar="False"
|
ShowInTaskbar="False"
|
||||||
WindowStartupLocation="CenterScreen"
|
WindowStartupLocation="CenterScreen"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<DockPanel Margin="{StaticResource Margin8}">
|
<DockPanel Margin="{StaticResource Margin8}">
|
||||||
<StackPanel
|
<StackPanel
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
DockPanel.Dock="Bottom"
|
DockPanel.Dock="Bottom"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<Button
|
<Button
|
||||||
@@ -55,77 +55,77 @@
|
|||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbDisplayGUI}" />
|
Text="{x:Static resx:ResUI.TbDisplayGUI}" />
|
||||||
|
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtGlobalHotkey0"
|
x:Name="txtGlobalHotkey0"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
IsReadOnly="True" />
|
IsReadOnly="True" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbClearSystemProxy}" />
|
Text="{x:Static resx:ResUI.TbClearSystemProxy}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtGlobalHotkey1"
|
x:Name="txtGlobalHotkey1"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
IsReadOnly="True" />
|
IsReadOnly="True" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSetSystemProxy}" />
|
Text="{x:Static resx:ResUI.TbSetSystemProxy}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtGlobalHotkey2"
|
x:Name="txtGlobalHotkey2"
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
IsReadOnly="True" />
|
IsReadOnly="True" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbNotChangeSystemProxy}" />
|
Text="{x:Static resx:ResUI.TbNotChangeSystemProxy}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtGlobalHotkey3"
|
x:Name="txtGlobalHotkey3"
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
IsReadOnly="True" />
|
IsReadOnly="True" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="5"
|
Grid.Row="5"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSystemProxyPac}" />
|
Text="{x:Static resx:ResUI.TbSystemProxyPac}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtGlobalHotkey4"
|
x:Name="txtGlobalHotkey4"
|
||||||
Grid.Row="5"
|
Grid.Row="5"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
IsReadOnly="True" />
|
IsReadOnly="True" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbGlobalHotkeySettingTip}" />
|
Text="{x:Static resx:ResUI.TbGlobalHotkeySettingTip}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|||||||
@@ -1,129 +1,138 @@
|
|||||||
using Avalonia.Controls;
|
using System.Reactive.Disposables;
|
||||||
|
using System.Text;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
using ReactiveUI;
|
||||||
|
using v2rayN.Desktop.Handler;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views
|
namespace v2rayN.Desktop.Views
|
||||||
{
|
{
|
||||||
public partial class GlobalHotkeySettingWindow : Window
|
public partial class GlobalHotkeySettingWindow : ReactiveWindow<GlobalHotkeySettingViewModel>
|
||||||
{
|
{
|
||||||
private static Config _config = default!;
|
private readonly List<object> _textBoxKeyEventItem = new();
|
||||||
private Dictionary<object, KeyEventItem> _TextBoxKeyEventItem = default!;
|
|
||||||
|
|
||||||
public GlobalHotkeySettingWindow()
|
public GlobalHotkeySettingWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
ViewModel = new GlobalHotkeySettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
|
btnReset.Click += btnReset_Click;
|
||||||
|
|
||||||
|
HotkeyHandler.Instance.IsPause = true;
|
||||||
|
this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false;
|
||||||
btnCancel.Click += (s, e) => this.Close();
|
btnCancel.Click += (s, e) => this.Close();
|
||||||
_config = AppHandler.Instance.Config;
|
|
||||||
//_config.globalHotkeys ??= new List<KeyEventItem>();
|
|
||||||
|
|
||||||
//txtGlobalHotkey0.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
this.WhenActivated(disposables =>
|
||||||
//txtGlobalHotkey1.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
{
|
||||||
//txtGlobalHotkey2.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
//txtGlobalHotkey3.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
});
|
||||||
//txtGlobalHotkey4.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
|
||||||
|
|
||||||
//HotkeyHandler.Instance.IsPause = true;
|
Init();
|
||||||
//this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false;
|
BindingData();
|
||||||
//InitData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//private void InitData()
|
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||||
//{
|
{
|
||||||
// _TextBoxKeyEventItem = new()
|
switch (action)
|
||||||
// {
|
{
|
||||||
// { txtGlobalHotkey0,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.ShowForm) },
|
case EViewAction.CloseWindow:
|
||||||
// { txtGlobalHotkey1,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxyClear) },
|
this.Close(true);
|
||||||
// { txtGlobalHotkey2,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxySet) },
|
break;
|
||||||
// { txtGlobalHotkey3,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxyUnchanged)},
|
}
|
||||||
// { txtGlobalHotkey4,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxyPac)}
|
return await Task.FromResult(true);
|
||||||
// };
|
}
|
||||||
// BindingData();
|
|
||||||
//}
|
|
||||||
|
|
||||||
//private void TxtGlobalHotkey_PreviewKeyDown(object? sender, KeyEventArgs e)
|
private void Init()
|
||||||
//{
|
{
|
||||||
// e.Handled = true;
|
_textBoxKeyEventItem.Add(txtGlobalHotkey0);
|
||||||
// var _ModifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift,
|
_textBoxKeyEventItem.Add(txtGlobalHotkey1);
|
||||||
// Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin};
|
_textBoxKeyEventItem.Add(txtGlobalHotkey2);
|
||||||
// _TextBoxKeyEventItem[sender].KeyCode = (int)(e.Key == Key.System ? (_ModifierKeys.Contains(e.SystemKey) ? Key.None : e.SystemKey) : (_ModifierKeys.Contains(e.Key) ? Key.None : e.Key));
|
_textBoxKeyEventItem.Add(txtGlobalHotkey3);
|
||||||
// _TextBoxKeyEventItem[sender].Alt = (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt;
|
_textBoxKeyEventItem.Add(txtGlobalHotkey4);
|
||||||
// _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 KeyEventItem GetKeyEventItemByEGlobalHotkey(List<KeyEventItem> KEList, EGlobalHotkey eg)
|
for (var index = 0; index < _textBoxKeyEventItem.Count; index++)
|
||||||
//{
|
{
|
||||||
// return JsonUtils.DeepCopy(KEList.Find((it) => it.eGlobalHotkey == eg) ?? new()
|
var sender = _textBoxKeyEventItem[index];
|
||||||
// {
|
if (sender is not TextBox txtBox)
|
||||||
// eGlobalHotkey = eg,
|
{
|
||||||
// Control = false,
|
continue;
|
||||||
// Alt = false,
|
}
|
||||||
// Shift = false,
|
txtBox.Tag = (EGlobalHotkey)index;
|
||||||
// KeyCode = null
|
txtBox.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||||
// });
|
}
|
||||||
//}
|
}
|
||||||
|
|
||||||
//private string KeyEventItemToString(KeyEventItem item)
|
private void TxtGlobalHotkey_PreviewKeyDown(object? sender, KeyEventArgs e)
|
||||||
//{
|
{
|
||||||
// var res = new StringBuilder();
|
e.Handled = true;
|
||||||
|
if (sender is not TextBox txtBox)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// if (item.Control) res.Append($"{ModifierKeys.Control}+");
|
var item = ViewModel?.GetKeyEventItem((EGlobalHotkey)txtBox.Tag);
|
||||||
// if (item.Shift) res.Append($"{ModifierKeys.Shift}+");
|
var modifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin };
|
||||||
// if (item.Alt) res.Append($"{ModifierKeys.Alt}+");
|
|
||||||
// if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
|
|
||||||
// res.Append($"{(Key)item.KeyCode}");
|
|
||||||
|
|
||||||
// return res.ToString();
|
item.KeyCode = (int)(e.Key == Key.System ? modifierKeys.Contains(Key.System) ? Key.None : Key.System : modifierKeys.Contains(e.Key) ? Key.None : e.Key);
|
||||||
//}
|
item.Alt = (e.KeyModifiers & KeyModifiers.Alt) == KeyModifiers.Alt;
|
||||||
|
item.Control = (e.KeyModifiers & KeyModifiers.Control) == KeyModifiers.Control;
|
||||||
|
item.Shift = (e.KeyModifiers & KeyModifiers.Shift) == KeyModifiers.Shift;
|
||||||
|
|
||||||
//private void BindingData()
|
txtBox.Text = KeyEventItemToString(item);
|
||||||
//{
|
}
|
||||||
// foreach (var item in _TextBoxKeyEventItem)
|
|
||||||
// {
|
|
||||||
// if (item.Value.KeyCode != null && (Key)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)
|
private void BindingData()
|
||||||
//{
|
{
|
||||||
// _config.globalHotkeys = _TextBoxKeyEventItem.Values.ToList();
|
foreach (var sender in _textBoxKeyEventItem)
|
||||||
|
{
|
||||||
|
if (sender is not TextBox txtBox)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// if (ConfigHandler.SaveConfig(_config, false) == 0)
|
var item = ViewModel?.GetKeyEventItem((EGlobalHotkey)txtBox.Tag);
|
||||||
// {
|
txtBox.Text = KeyEventItemToString(item);
|
||||||
// HotkeyHandler.Instance.ReLoad();
|
}
|
||||||
// this.Close();
|
}
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// UI.Show(ResUI.OperationFailed);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//private void btnReset_Click(object? sender, RoutedEventArgs e)
|
private void btnReset_Click(object sender, RoutedEventArgs e)
|
||||||
//{
|
{
|
||||||
// foreach (var k in _TextBoxKeyEventItem.Keys)
|
ViewModel?.ResetKeyEventItem();
|
||||||
// {
|
BindingData();
|
||||||
// _TextBoxKeyEventItem[k].Alt = false;
|
}
|
||||||
// _TextBoxKeyEventItem[k].Control = false;
|
|
||||||
// _TextBoxKeyEventItem[k].Shift = false;
|
|
||||||
// _TextBoxKeyEventItem[k].KeyCode = (int)Key.None;
|
|
||||||
// }
|
|
||||||
// BindingData();
|
|
||||||
//}
|
|
||||||
|
|
||||||
//private void GlobalHotkeySettingWindow_KeyDown(object? sender, KeyEventArgs e)
|
private string KeyEventItemToString(KeyEventItem? item)
|
||||||
//{
|
{
|
||||||
// if (e.Key == Key.Escape)
|
if (item == null)
|
||||||
// {
|
{
|
||||||
// this.Close();
|
return string.Empty;
|
||||||
// }
|
}
|
||||||
//}
|
var res = new StringBuilder();
|
||||||
|
|
||||||
|
if (item.Control)
|
||||||
|
{
|
||||||
|
res.Append($"{KeyModifiers.Control} +");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.Shift)
|
||||||
|
{
|
||||||
|
res.Append($"{KeyModifiers.Shift} +");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.Alt)
|
||||||
|
{
|
||||||
|
res.Append($"{KeyModifiers.Alt} +");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
|
||||||
|
{
|
||||||
|
res.Append($"{(Key)item.KeyCode}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using MsBox.Avalonia.Enums;
|
|||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Splat;
|
using Splat;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
using v2rayN.Desktop.Handler;
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views
|
namespace v2rayN.Desktop.Views
|
||||||
{
|
{
|
||||||
@@ -138,8 +139,7 @@ namespace v2rayN.Desktop.Views
|
|||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
|
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
|
||||||
|
HotkeyHandler.Instance.Init(_config, OnHotkeyHandler);
|
||||||
menuGlobalHotkeySetting.IsVisible = false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -156,7 +156,6 @@ namespace v2rayN.Desktop.Views
|
|||||||
|
|
||||||
RestoreUI();
|
RestoreUI();
|
||||||
AddHelpMenuItem();
|
AddHelpMenuItem();
|
||||||
//WindowsHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null);
|
|
||||||
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +232,7 @@ namespace v2rayN.Desktop.Views
|
|||||||
StorageUI();
|
StorageUI();
|
||||||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
{
|
{
|
||||||
|
HotkeyHandler.Instance.Dispose();
|
||||||
desktop.Shutdown();
|
desktop.Shutdown();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -247,7 +247,10 @@ namespace v2rayN.Desktop.Views
|
|||||||
|
|
||||||
case EViewAction.AddServerViaClipboard:
|
case EViewAction.AddServerViaClipboard:
|
||||||
var clipboardData = await AvaUtils.GetClipboardData(this);
|
var clipboardData = await AvaUtils.GetClipboardData(this);
|
||||||
ViewModel?.AddServerViaClipboardAsync(clipboardData);
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
await ViewModel.AddServerViaClipboardAsync(clipboardData);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.AdjustMainLvColWidth:
|
case EViewAction.AdjustMainLvColWidth:
|
||||||
@@ -268,21 +271,12 @@ namespace v2rayN.Desktop.Views
|
|||||||
ShowHideWindow(null);
|
ShowHideWindow(null);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//case EGlobalHotkey.SystemProxyClear:
|
case EGlobalHotkey.SystemProxyClear:
|
||||||
// ViewModel?.SetListenerType(ESysProxyType.ForcedClear);
|
case EGlobalHotkey.SystemProxySet:
|
||||||
// break;
|
case EGlobalHotkey.SystemProxyUnchanged:
|
||||||
|
case EGlobalHotkey.SystemProxyPac:
|
||||||
//case EGlobalHotkey.SystemProxySet:
|
Locator.Current.GetService<StatusBarViewModel>()?.SetListenerType((ESysProxyType)((int)e - 1));
|
||||||
// ViewModel?.SetListenerType(ESysProxyType.ForcedChange);
|
break;
|
||||||
// break;
|
|
||||||
|
|
||||||
//case EGlobalHotkey.SystemProxyUnchanged:
|
|
||||||
// ViewModel?.SetListenerType(ESysProxyType.Unchanged);
|
|
||||||
// break;
|
|
||||||
|
|
||||||
//case EGlobalHotkey.SystemProxyPac:
|
|
||||||
// ViewModel?.SetListenerType(ESysProxyType.Pac);
|
|
||||||
// break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +297,10 @@ namespace v2rayN.Desktop.Views
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowCloseReason.ApplicationShutdown or WindowCloseReason.OSShutdown:
|
case WindowCloseReason.ApplicationShutdown or WindowCloseReason.OSShutdown:
|
||||||
await ViewModel?.MyAppExitAsync(true);
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
await ViewModel.MyAppExitAsync(true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +315,10 @@ namespace v2rayN.Desktop.Views
|
|||||||
{
|
{
|
||||||
case Key.V:
|
case Key.V:
|
||||||
var clipboardData = await AvaUtils.GetClipboardData(this);
|
var clipboardData = await AvaUtils.GetClipboardData(this);
|
||||||
ViewModel?.AddServerViaClipboardAsync(clipboardData);
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
await ViewModel.AddServerViaClipboardAsync(clipboardData);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Key.S:
|
case Key.S:
|
||||||
@@ -367,7 +367,11 @@ namespace v2rayN.Desktop.Views
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await ViewModel?.ScanImageResult(fileName);
|
|
||||||
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
await ViewModel.ScanImageResult(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MenuCheckUpdate_Click(object? sender, RoutedEventArgs e)
|
private void MenuCheckUpdate_Click(object? sender, RoutedEventArgs e)
|
||||||
@@ -391,8 +395,10 @@ namespace v2rayN.Desktop.Views
|
|||||||
|
|
||||||
_blCloseByUser = true;
|
_blCloseByUser = true;
|
||||||
StorageUI();
|
StorageUI();
|
||||||
|
if (ViewModel != null)
|
||||||
await ViewModel?.MyAppExitAsync(false);
|
{
|
||||||
|
await ViewModel.MyAppExitAsync(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Event
|
#endregion Event
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<DockPanel Margin="2">
|
<DockPanel Margin="2">
|
||||||
<WrapPanel
|
<WrapPanel
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
DockPanel.Dock="Top"
|
DockPanel.Dock="Top"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
|
|
||||||
@@ -37,6 +37,8 @@
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnClear"
|
x:Name="btnClear"
|
||||||
|
Width="{StaticResource IconButtonWidth}"
|
||||||
|
Height="{StaticResource IconButtonHeight}"
|
||||||
Margin="{StaticResource MarginLr8}"
|
Margin="{StaticResource MarginLr8}"
|
||||||
Classes="Success"
|
Classes="Success"
|
||||||
Click="menuMsgViewClear_Click"
|
Click="menuMsgViewClear_Click"
|
||||||
|
|||||||
@@ -248,7 +248,10 @@ namespace v2rayN.Desktop.Views
|
|||||||
|
|
||||||
private void ClbdestOverride_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
private void ClbdestOverride_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ namespace v2rayN.Desktop.Views
|
|||||||
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.RemoveInvalidServerResultCmd, v => v.menuRemoveInvalidServerResult).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.RemoveInvalidServerResultCmd, v => v.menuRemoveInvalidServerResult).DisposeWith(disposables);
|
||||||
|
|
||||||
//servers export
|
//servers export
|
||||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigClipboardCmd, v => v.menuExport2ClientConfigClipboard).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigClipboardCmd, v => v.menuExport2ClientConfigClipboard).DisposeWith(disposables);
|
||||||
@@ -102,11 +102,16 @@ namespace v2rayN.Desktop.Views
|
|||||||
private async void LstProfiles_Sorting(object? sender, DataGridColumnEventArgs e)
|
private async void LstProfiles_Sorting(object? sender, DataGridColumnEventArgs e)
|
||||||
{
|
{
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
await ViewModel?.SortServer(e.Column.Tag.ToString());
|
|
||||||
|
if (ViewModel != null && e.Column?.Tag?.ToString() != null)
|
||||||
|
{
|
||||||
|
await ViewModel.SortServer(e.Column.Tag.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
e.Handled = false;
|
e.Handled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region Event
|
#region Event
|
||||||
|
|
||||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||||
{
|
{
|
||||||
@@ -179,7 +184,9 @@ namespace v2rayN.Desktop.Views
|
|||||||
|
|
||||||
case EViewAction.DispatcherRefreshServersBiz:
|
case EViewAction.DispatcherRefreshServersBiz:
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
ViewModel?.RefreshServersBiz(),
|
{
|
||||||
|
_ = RefreshServersBiz();
|
||||||
|
},
|
||||||
DispatcherPriority.Default);
|
DispatcherPriority.Default);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -198,9 +205,25 @@ namespace v2rayN.Desktop.Views
|
|||||||
await DialogHost.Show(dialog);
|
await DialogHost.Show(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task RefreshServersBiz()
|
||||||
|
{
|
||||||
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
await ViewModel.RefreshServersBiz();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstProfiles.SelectedIndex > 0)
|
||||||
|
{
|
||||||
|
lstProfiles.ScrollIntoView(lstProfiles.SelectedItem, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void lstProfiles_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
private void lstProfiles_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LstProfiles_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
private void LstProfiles_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||||
@@ -333,9 +356,9 @@ namespace v2rayN.Desktop.Views
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion Event
|
#endregion Event
|
||||||
|
|
||||||
//#region UI
|
#region UI
|
||||||
|
|
||||||
private void RestoreUI()
|
private void RestoreUI()
|
||||||
{
|
{
|
||||||
@@ -388,9 +411,9 @@ namespace v2rayN.Desktop.Views
|
|||||||
_config.UiItem.MainColumnItem = lvColumnItem;
|
_config.UiItem.MainColumnItem = lvColumnItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion UI
|
#endregion UI
|
||||||
|
|
||||||
//#region Drag and Drop
|
#region Drag and Drop
|
||||||
|
|
||||||
//private Point startPoint = new();
|
//private Point startPoint = new();
|
||||||
//private int startIndex = -1;
|
//private int startIndex = -1;
|
||||||
@@ -480,6 +503,6 @@ namespace v2rayN.Desktop.Views
|
|||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//#endregion Drag and Drop
|
#endregion Drag and Drop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,12 +85,18 @@ namespace v2rayN.Desktop.Views
|
|||||||
|
|
||||||
private void ClbProtocol_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
private void ClbProtocol_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.ProtocolItems = clbProtocol.SelectedItems.Cast<string>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.ProtocolItems = clbProtocol.SelectedItems.Cast<string>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClbInboundTag_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
private void ClbInboundTag_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.InboundTagItems = clbInboundTag.SelectedItems.Cast<string>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.InboundTagItems = clbInboundTag.SelectedItems.Cast<string>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void linkRuleobjectDoc_Click(object? sender, RoutedEventArgs e)
|
private void linkRuleobjectDoc_Click(object? sender, RoutedEventArgs e)
|
||||||
|
|||||||
@@ -167,7 +167,10 @@ namespace v2rayN.Desktop.Views
|
|||||||
|
|
||||||
private void lstRules_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
private void lstRules_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.SelectedSources = lstRules.SelectedItems.Cast<RulesItemModel>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.SelectedSources = lstRules.SelectedItems.Cast<RulesItemModel>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LstRules_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
private void LstRules_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||||
|
|||||||
@@ -108,7 +108,10 @@ namespace v2rayN.Desktop.Views
|
|||||||
|
|
||||||
private void lstRoutings_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
private void lstRoutings_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.SelectedSources = lstRoutings.SelectedItems.Cast<RoutingItemModel>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.SelectedSources = lstRoutings.SelectedItems.Cast<RoutingItemModel>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LstRoutings_DoubleTapped(object? sender, TappedEventArgs e)
|
private void LstRoutings_DoubleTapped(object? sender, TappedEventArgs e)
|
||||||
|
|||||||
@@ -84,7 +84,10 @@ namespace v2rayN.Desktop.Views
|
|||||||
|
|
||||||
private void LstSubscription_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
private void LstSubscription_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.SelectedSources = lstSubscription.SelectedItems.Cast<SubItem>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.SelectedSources = lstSubscription.SelectedItems.Cast<SubItem>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void menuClose_Click(object? sender, RoutedEventArgs e)
|
private void menuClose_Click(object? sender, RoutedEventArgs e)
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectCapability Include="Avalonia" />
|
<ProjectCapability Include="Avalonia" />
|
||||||
<AvaloniaResource Include="Assets\**" />
|
<AvaloniaResource Include="Assets\**" />
|
||||||
|
<ProjectReference Include="..\GlobalHotKeys\src\GlobalHotKeys\GlobalHotKeys.csproj" />
|
||||||
<ProjectReference Include="..\ServiceLib\ServiceLib.csproj" />
|
<ProjectReference Include="..\ServiceLib\ServiceLib.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "v2rayN.Desktop", "v2rayN.De
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AmazTool", "AmazTool\AmazTool.csproj", "{47D68B1C-601C-4C69-873B-FFF0DC13EC97}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AmazTool", "AmazTool\AmazTool.csproj", "{47D68B1C-601C-4C69-873B-FFF0DC13EC97}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GlobalHotKeys", "GlobalHotKeys\src\GlobalHotKeys\GlobalHotKeys.csproj", "{CB3DE54F-3A26-AE02-1299-311132C32156}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -33,6 +35,10 @@ Global
|
|||||||
{47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Release|Any CPU.Build.0 = Release|Any CPU
|
{47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CB3DE54F-3A26-AE02-1299-311132C32156}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CB3DE54F-3A26-AE02-1299-311132C32156}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CB3DE54F-3A26-AE02-1299-311132C32156}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CB3DE54F-3A26-AE02-1299-311132C32156}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -11,15 +11,8 @@ namespace v2rayN.Handler
|
|||||||
{
|
{
|
||||||
private static readonly Lazy<HotkeyHandler> _instance = new(() => new());
|
private static readonly Lazy<HotkeyHandler> _instance = new(() => new());
|
||||||
public static HotkeyHandler Instance = _instance.Value;
|
public static HotkeyHandler Instance = _instance.Value;
|
||||||
|
|
||||||
private const int WmHotkey = 0x0312;
|
private const int WmHotkey = 0x0312;
|
||||||
|
private readonly Dictionary<int, List<EGlobalHotkey>> _hotkeyTriggerDic = new();
|
||||||
private Config _config
|
|
||||||
{
|
|
||||||
get => AppHandler.Instance.Config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<int, List<EGlobalHotkey>> _hotkeyTriggerDic;
|
|
||||||
|
|
||||||
public bool IsPause { get; set; } = false;
|
public bool IsPause { get; set; } = false;
|
||||||
|
|
||||||
@@ -29,7 +22,6 @@ namespace v2rayN.Handler
|
|||||||
|
|
||||||
public HotkeyHandler()
|
public HotkeyHandler()
|
||||||
{
|
{
|
||||||
_hotkeyTriggerDic = new();
|
|
||||||
ComponentDispatcher.ThreadPreprocessMessage += OnThreadPreProcessMessage;
|
ComponentDispatcher.ThreadPreprocessMessage += OnThreadPreProcessMessage;
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
@@ -37,20 +29,27 @@ namespace v2rayN.Handler
|
|||||||
private void Init()
|
private void Init()
|
||||||
{
|
{
|
||||||
_hotkeyTriggerDic.Clear();
|
_hotkeyTriggerDic.Clear();
|
||||||
if (_config.GlobalHotkeys == null)
|
foreach (var item in AppHandler.Instance.Config.GlobalHotkeys)
|
||||||
return;
|
|
||||||
foreach (var item in _config.GlobalHotkeys)
|
|
||||||
{
|
{
|
||||||
if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
|
if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
|
||||||
{
|
{
|
||||||
int key = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode);
|
var key = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode);
|
||||||
KeyModifiers modifiers = KeyModifiers.None;
|
var modifiers = KeyModifiers.None;
|
||||||
if (item.Control)
|
if (item.Control)
|
||||||
|
{
|
||||||
modifiers |= KeyModifiers.Ctrl;
|
modifiers |= KeyModifiers.Ctrl;
|
||||||
|
}
|
||||||
|
|
||||||
if (item.Shift)
|
if (item.Shift)
|
||||||
|
{
|
||||||
modifiers |= KeyModifiers.Shift;
|
modifiers |= KeyModifiers.Shift;
|
||||||
|
}
|
||||||
|
|
||||||
if (item.Alt)
|
if (item.Alt)
|
||||||
|
{
|
||||||
modifiers |= KeyModifiers.Alt;
|
modifiers |= KeyModifiers.Alt;
|
||||||
|
}
|
||||||
|
|
||||||
key = (key << 16) | (int)modifiers;
|
key = (key << 16) | (int)modifiers;
|
||||||
if (!_hotkeyTriggerDic.ContainsKey(key))
|
if (!_hotkeyTriggerDic.ContainsKey(key))
|
||||||
{
|
{
|
||||||
@@ -59,7 +58,9 @@ namespace v2rayN.Handler
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!_hotkeyTriggerDic[key].Contains(item.EGlobalHotkey))
|
if (!_hotkeyTriggerDic[key].Contains(item.EGlobalHotkey))
|
||||||
|
{
|
||||||
_hotkeyTriggerDic[key].Add(item.EGlobalHotkey);
|
_hotkeyTriggerDic[key].Add(item.EGlobalHotkey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,8 +71,8 @@ namespace v2rayN.Handler
|
|||||||
foreach (var _hotkeyCode in _hotkeyTriggerDic.Keys)
|
foreach (var _hotkeyCode in _hotkeyTriggerDic.Keys)
|
||||||
{
|
{
|
||||||
var hotkeyInfo = GetHotkeyInfo(_hotkeyCode);
|
var hotkeyInfo = GetHotkeyInfo(_hotkeyCode);
|
||||||
bool isSuccess = false;
|
var isSuccess = false;
|
||||||
string msg;
|
var msg = string.Empty;
|
||||||
|
|
||||||
Application.Current?.Dispatcher.Invoke(() =>
|
Application.Current?.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
@@ -106,29 +107,38 @@ namespace v2rayN.Handler
|
|||||||
Load();
|
Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
private (int fsModifiers, int vKey, string hotkeyStr, List<string> Names) GetHotkeyInfo(int hotkeycode)
|
private (int fsModifiers, int vKey, string hotkeyStr, List<string> Names) GetHotkeyInfo(int hotkeyCode)
|
||||||
{
|
{
|
||||||
var _fsModifiers = hotkeycode & 0xffff;
|
var fsModifiers = hotkeyCode & 0xffff;
|
||||||
var _vkey = (hotkeycode >> 16) & 0xffff;
|
var vKey = (hotkeyCode >> 16) & 0xffff;
|
||||||
var _hotkeyStr = new StringBuilder();
|
var hotkeyStr = new StringBuilder();
|
||||||
var _names = new List<string>();
|
var names = new List<string>();
|
||||||
|
|
||||||
var mdif = (KeyModifiers)_fsModifiers;
|
var modify = (KeyModifiers)fsModifiers;
|
||||||
var key = KeyInterop.KeyFromVirtualKey(_vkey);
|
var key = KeyInterop.KeyFromVirtualKey(vKey);
|
||||||
if ((mdif & KeyModifiers.Ctrl) == KeyModifiers.Ctrl)
|
if ((modify & 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());
|
hotkeyStr.Append($"{KeyModifiers.Ctrl}+");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (_fsModifiers, _vkey, _hotkeyStr.ToString(), _names);
|
if ((modify & KeyModifiers.Alt) == KeyModifiers.Alt)
|
||||||
|
{
|
||||||
|
hotkeyStr.Append($"{KeyModifiers.Alt}+");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((modify & 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)
|
private void OnThreadPreProcessMessage(ref MSG msg, ref bool handled)
|
||||||
@@ -138,21 +148,18 @@ namespace v2rayN.Handler
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handled = true;
|
handled = true;
|
||||||
var _hotKeyCode = (int)msg.lParam;
|
var hotKeyCode = (int)msg.lParam;
|
||||||
if (IsPause)
|
if (IsPause)
|
||||||
{
|
{
|
||||||
Application.Current?.Dispatcher.Invoke(() =>
|
Application.Current?.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
UIElement? element = Keyboard.FocusedElement as UIElement;
|
if (Keyboard.FocusedElement is UIElement element)
|
||||||
if (element != null)
|
|
||||||
{
|
{
|
||||||
var _keyEventArgs = new KeyEventArgs(Keyboard.PrimaryDevice,
|
var keyEventArgs = new KeyEventArgs(Keyboard.PrimaryDevice, PresentationSource.FromVisual(element), 0, KeyInterop.KeyFromVirtualKey(GetHotkeyInfo(hotKeyCode).vKey))
|
||||||
PresentationSource.FromVisual(element), 0,
|
|
||||||
KeyInterop.KeyFromVirtualKey(GetHotkeyInfo(_hotKeyCode).vKey))
|
|
||||||
{
|
{
|
||||||
RoutedEvent = UIElement.KeyDownEvent
|
RoutedEvent = UIElement.KeyDownEvent
|
||||||
};
|
};
|
||||||
element.RaiseEvent(_keyEventArgs);
|
element.RaiseEvent(keyEventArgs);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<reactiveui:ReactiveWindow
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.AddServer2Window"
|
x:Class="v2rayN.Views.AddServer2Window"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
xmlns:reactiveui="http://reactiveui.net"
|
xmlns:reactiveui="http://reactiveui.net"
|
||||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||||
Title="v2rayN"
|
Title="{x:Static resx:ResUI.menuAddCustomServer}"
|
||||||
Width="700"
|
Width="700"
|
||||||
Height="500"
|
Height="500"
|
||||||
x:TypeArguments="vms:AddServer2ViewModel"
|
x:TypeArguments="vms:AddServer2ViewModel"
|
||||||
@@ -198,4 +198,4 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</reactiveui:ReactiveWindow>
|
</reactiveui:ReactiveWindow>
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
<reactiveui:ReactiveWindow
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.GlobalHotkeySettingWindow"
|
x:Class="v2rayN.Views.GlobalHotkeySettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
|
||||||
xmlns:reactiveui="http://reactiveui.net"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:reactiveui="http://reactiveui.net"
|
||||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||||
Title="{x:Static resx:ResUI.menuSetting}"
|
Title="{x:Static resx:ResUI.menuGlobalHotkeySetting}"
|
||||||
Width="700"
|
Width="700"
|
||||||
Height="500"
|
Height="500"
|
||||||
x:TypeArguments="vms:SubEditViewModel"
|
x:TypeArguments="vms:GlobalHotkeySettingViewModel"
|
||||||
KeyDown="GlobalHotkeySettingWindow_KeyDown"
|
|
||||||
ShowInTaskbar="False"
|
ShowInTaskbar="False"
|
||||||
Style="{StaticResource WindowGlobal}"
|
Style="{StaticResource WindowGlobal}"
|
||||||
WindowStartupLocation="CenterScreen"
|
WindowStartupLocation="CenterScreen"
|
||||||
@@ -92,7 +91,6 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
AcceptsReturn="True"
|
AcceptsReturn="True"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
PreviewKeyDown="TxtGlobalHotkey_PreviewKeyDown"
|
|
||||||
Style="{StaticResource MyOutlinedTextBox}" />
|
Style="{StaticResource MyOutlinedTextBox}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
@@ -110,7 +108,6 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
AcceptsReturn="True"
|
AcceptsReturn="True"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
PreviewKeyDown="TxtGlobalHotkey_PreviewKeyDown"
|
|
||||||
Style="{StaticResource MyOutlinedTextBox}" />
|
Style="{StaticResource MyOutlinedTextBox}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
@@ -128,7 +125,6 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
AcceptsReturn="True"
|
AcceptsReturn="True"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
PreviewKeyDown="TxtGlobalHotkey_PreviewKeyDown"
|
|
||||||
Style="{StaticResource MyOutlinedTextBox}" />
|
Style="{StaticResource MyOutlinedTextBox}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
@@ -145,7 +141,6 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
AcceptsReturn="True"
|
AcceptsReturn="True"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
PreviewKeyDown="TxtGlobalHotkey_PreviewKeyDown"
|
|
||||||
Style="{StaticResource MyOutlinedTextBox}" />
|
Style="{StaticResource MyOutlinedTextBox}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="5"
|
Grid.Row="5"
|
||||||
@@ -162,7 +157,6 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
AcceptsReturn="True"
|
AcceptsReturn="True"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
PreviewKeyDown="TxtGlobalHotkey_PreviewKeyDown"
|
|
||||||
Style="{StaticResource MyOutlinedTextBox}" />
|
Style="{StaticResource MyOutlinedTextBox}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|||||||
@@ -1,140 +1,139 @@
|
|||||||
|
using System.Reactive.Disposables;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using ReactiveUI;
|
||||||
using v2rayN.Handler;
|
using v2rayN.Handler;
|
||||||
|
|
||||||
namespace v2rayN.Views
|
namespace v2rayN.Views
|
||||||
{
|
{
|
||||||
public partial class GlobalHotkeySettingWindow
|
public partial class GlobalHotkeySettingWindow
|
||||||
{
|
{
|
||||||
private static Config _config = default!;
|
private readonly List<object> _textBoxKeyEventItem = new();
|
||||||
private Dictionary<object, KeyEventItem> _TextBoxKeyEventItem = default!;
|
|
||||||
|
|
||||||
public GlobalHotkeySettingWindow()
|
public GlobalHotkeySettingWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.Owner = Application.Current.MainWindow;
|
this.Owner = Application.Current.MainWindow;
|
||||||
_config = AppHandler.Instance.Config;
|
|
||||||
_config.GlobalHotkeys ??= new List<KeyEventItem>();
|
ViewModel = new GlobalHotkeySettingViewModel(UpdateViewHandler);
|
||||||
|
|
||||||
btnReset.Click += btnReset_Click;
|
btnReset.Click += btnReset_Click;
|
||||||
btnSave.Click += btnSave_ClickAsync;
|
|
||||||
|
|
||||||
txtGlobalHotkey0.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
|
||||||
txtGlobalHotkey1.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
|
||||||
txtGlobalHotkey2.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
|
||||||
txtGlobalHotkey3.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
|
||||||
txtGlobalHotkey4.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
|
||||||
|
|
||||||
HotkeyHandler.Instance.IsPause = true;
|
HotkeyHandler.Instance.IsPause = true;
|
||||||
this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false;
|
this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false;
|
||||||
WindowsUtils.SetDarkBorder(this, _config.UiItem.CurrentTheme);
|
|
||||||
InitData();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitData()
|
this.WhenActivated(disposables =>
|
||||||
{
|
|
||||||
_TextBoxKeyEventItem = new()
|
|
||||||
{
|
{
|
||||||
{ txtGlobalHotkey0,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.ShowForm) },
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
{ txtGlobalHotkey1,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.SystemProxyClear) },
|
});
|
||||||
{ txtGlobalHotkey2,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.SystemProxySet) },
|
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme);
|
||||||
{ txtGlobalHotkey3,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.SystemProxyUnchanged)},
|
|
||||||
{ txtGlobalHotkey4,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.SystemProxyPac)}
|
Init();
|
||||||
};
|
|
||||||
BindingData();
|
BindingData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TxtGlobalHotkey_PreviewKeyDown(object sender, KeyEventArgs e)
|
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case EViewAction.CloseWindow:
|
||||||
|
this.DialogResult = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return await Task.FromResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Init()
|
||||||
|
{
|
||||||
|
_textBoxKeyEventItem.Add(txtGlobalHotkey0);
|
||||||
|
_textBoxKeyEventItem.Add(txtGlobalHotkey1);
|
||||||
|
_textBoxKeyEventItem.Add(txtGlobalHotkey2);
|
||||||
|
_textBoxKeyEventItem.Add(txtGlobalHotkey3);
|
||||||
|
_textBoxKeyEventItem.Add(txtGlobalHotkey4);
|
||||||
|
|
||||||
|
for (var index = 0; index < _textBoxKeyEventItem.Count; index++)
|
||||||
|
{
|
||||||
|
var sender = _textBoxKeyEventItem[index];
|
||||||
|
if (sender is not TextBox txtBox)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
txtBox.Tag = (EGlobalHotkey)index;
|
||||||
|
txtBox.PreviewKeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TxtGlobalHotkey_PreviewKeyDown(object? sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
var _ModifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift,
|
if (sender is not TextBox txtBox)
|
||||||
Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin};
|
|
||||||
_TextBoxKeyEventItem[sender].KeyCode = (int)(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 KeyEventItem GetKeyEventItemByEGlobalHotkey(List<KeyEventItem> KEList, EGlobalHotkey eg)
|
|
||||||
{
|
|
||||||
return JsonUtils.DeepCopy(KEList.Find((it) => it.EGlobalHotkey == eg) ?? new()
|
|
||||||
{
|
{
|
||||||
EGlobalHotkey = eg,
|
return;
|
||||||
Control = false,
|
}
|
||||||
Alt = false,
|
|
||||||
Shift = false,
|
|
||||||
KeyCode = null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private string KeyEventItemToString(KeyEventItem item)
|
var item = ViewModel?.GetKeyEventItem((EGlobalHotkey)txtBox.Tag);
|
||||||
{
|
var modifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin };
|
||||||
var res = new StringBuilder();
|
|
||||||
|
|
||||||
if (item.Control)
|
item.KeyCode = (int)(e.Key == Key.System ? (modifierKeys.Contains(e.SystemKey) ? Key.None : e.SystemKey) : (modifierKeys.Contains(e.Key) ? Key.None : e.Key));
|
||||||
res.Append($"{ModifierKeys.Control}+");
|
item.Alt = (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt;
|
||||||
if (item.Shift)
|
item.Control = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control;
|
||||||
res.Append($"{ModifierKeys.Shift}+");
|
item.Shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
|
||||||
if (item.Alt)
|
|
||||||
res.Append($"{ModifierKeys.Alt}+");
|
|
||||||
if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
|
|
||||||
res.Append($"{(Key)item.KeyCode}");
|
|
||||||
|
|
||||||
return res.ToString();
|
txtBox.Text = KeyEventItemToString(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BindingData()
|
private void BindingData()
|
||||||
{
|
{
|
||||||
foreach (var item in _TextBoxKeyEventItem)
|
foreach (var sender in _textBoxKeyEventItem)
|
||||||
{
|
{
|
||||||
if (item.Value.KeyCode != null && (Key)item.Value.KeyCode != Key.None)
|
if (sender is not TextBox txtBox)
|
||||||
{
|
{
|
||||||
(item.Key as TextBox)!.Text = KeyEventItemToString(item.Value);
|
continue;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
(item.Key as TextBox)!.Text = string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void btnSave_ClickAsync(object sender, RoutedEventArgs e)
|
var item = ViewModel?.GetKeyEventItem((EGlobalHotkey)txtBox.Tag);
|
||||||
{
|
txtBox.Text = KeyEventItemToString(item);
|
||||||
_config.GlobalHotkeys = _TextBoxKeyEventItem.Values.ToList();
|
|
||||||
|
|
||||||
if (await ConfigHandler.SaveConfig(_config) == 0)
|
|
||||||
{
|
|
||||||
HotkeyHandler.Instance.ReLoad();
|
|
||||||
this.DialogResult = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UI.Show(ResUI.OperationFailed);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnReset_Click(object sender, RoutedEventArgs e)
|
private void btnReset_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
foreach (var k in _TextBoxKeyEventItem.Keys)
|
ViewModel?.ResetKeyEventItem();
|
||||||
{
|
|
||||||
_TextBoxKeyEventItem[k].Alt = false;
|
|
||||||
_TextBoxKeyEventItem[k].Control = false;
|
|
||||||
_TextBoxKeyEventItem[k].Shift = false;
|
|
||||||
_TextBoxKeyEventItem[k].KeyCode = (int)Key.None;
|
|
||||||
}
|
|
||||||
BindingData();
|
BindingData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GlobalHotkeySettingWindow_KeyDown(object sender, KeyEventArgs e)
|
private string KeyEventItemToString(KeyEventItem? item)
|
||||||
{
|
{
|
||||||
if (e.Key == Key.Escape)
|
if (item == null)
|
||||||
{
|
{
|
||||||
this.Close();
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
var res = new StringBuilder();
|
||||||
|
|
||||||
|
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 && (Key)item.KeyCode != Key.None)
|
||||||
|
{
|
||||||
|
res.Append($"{(Key)item.KeyCode}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,7 +259,10 @@ namespace v2rayN.Views
|
|||||||
|
|
||||||
private void ClbdestOverride_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
private void ClbdestOverride_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ namespace v2rayN.Views
|
|||||||
case EViewAction.DispatcherRefreshServersBiz:
|
case EViewAction.DispatcherRefreshServersBiz:
|
||||||
Application.Current?.Dispatcher.Invoke((() =>
|
Application.Current?.Dispatcher.Invoke((() =>
|
||||||
{
|
{
|
||||||
ViewModel?.RefreshServersBiz();
|
_ = RefreshServersBiz();
|
||||||
}), DispatcherPriority.Normal);
|
}), DispatcherPriority.Normal);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -186,9 +186,25 @@ namespace v2rayN.Views
|
|||||||
await DialogHost.Show(dialog, "RootDialog");
|
await DialogHost.Show(dialog, "RootDialog");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task RefreshServersBiz()
|
||||||
|
{
|
||||||
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
await ViewModel.RefreshServersBiz();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstProfiles.SelectedIndex > 0)
|
||||||
|
{
|
||||||
|
lstProfiles.ScrollIntoView(lstProfiles.SelectedItem, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void lstProfiles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
private void lstProfiles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
|
private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
|
||||||
|
|||||||
@@ -79,12 +79,18 @@ namespace v2rayN.Views
|
|||||||
|
|
||||||
private void ClbProtocol_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
private void ClbProtocol_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.ProtocolItems = clbProtocol.SelectedItems.Cast<string>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.ProtocolItems = clbProtocol.SelectedItems.Cast<string>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClbInboundTag_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
private void ClbInboundTag_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.InboundTagItems = clbInboundTag.SelectedItems.Cast<string>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.InboundTagItems = clbInboundTag.SelectedItems.Cast<string>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void linkRuleobjectDoc_Click(object sender, RoutedEventArgs e)
|
private void linkRuleobjectDoc_Click(object sender, RoutedEventArgs e)
|
||||||
|
|||||||
@@ -162,7 +162,10 @@ namespace v2rayN.Views
|
|||||||
|
|
||||||
private void lstRules_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
private void lstRules_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.SelectedSources = lstRules.SelectedItems.Cast<RulesItemModel>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.SelectedSources = lstRules.SelectedItems.Cast<RulesItemModel>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LstRules_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
private void LstRules_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
|
|||||||
@@ -113,7 +113,10 @@ namespace v2rayN.Views
|
|||||||
|
|
||||||
private void lstRoutings_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
private void lstRoutings_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.SelectedSources = lstRoutings.SelectedItems.Cast<RoutingItemModel>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.SelectedSources = lstRoutings.SelectedItems.Cast<RoutingItemModel>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LstRoutings_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
private void LstRoutings_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
|
|||||||
@@ -94,7 +94,10 @@ namespace v2rayN.Views
|
|||||||
|
|
||||||
private void LstSubscription_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
private void LstSubscription_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.SelectedSources = lstSubscription.SelectedItems.Cast<SubItem>().ToList();
|
if (ViewModel != null)
|
||||||
|
{
|
||||||
|
ViewModel.SelectedSources = lstSubscription.SelectedItems.Cast<SubItem>().ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void menuClose_Click(object sender, System.Windows.RoutedEventArgs e)
|
private void menuClose_Click(object sender, System.Windows.RoutedEventArgs e)
|
||||||
|
|||||||
Reference in New Issue
Block a user