< ver> + 1.1.7

<feat> + 翻译工具
This commit is contained in:
nsnail 2022-12-17 11:32:35 +08:00
commit 5a499428a2
16 changed files with 421 additions and 296 deletions

View File

@ -1,8 +1,4 @@
<wpf:ResourceDictionary xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xml:space="preserve"> <wpf:ResourceDictionary xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xml:space="preserve">
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/ReSpeller/ReSpellerEnabled/@EntryValue">False</s:Boolean> <s:Boolean x:Key="/Default/ReSpeller/ReSpellerEnabled/@EntryValue">False</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64> <s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64> <s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
@ -16,7 +12,6 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt; <s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;
&lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt; &lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt;
&lt;TypePattern&gt; &lt;TypePattern&gt;
@ -57,5 +52,4 @@
&lt;/Entry&gt; &lt;/Entry&gt;
&lt;/TypePattern&gt; &lt;/TypePattern&gt;
&lt;/Patterns&gt;</s:String> &lt;/Patterns&gt;</s:String>
</wpf:ResourceDictionary> </wpf:ResourceDictionary>

View File

@ -1 +1,2 @@
git reset --hard | git clean -d -fx . git reset --hard
git clean -d -fx .

View File

@ -24,5 +24,5 @@ internal static class AssemblyInfo
public const string ASSEMBLY_PRODUCT = "dot"; public const string ASSEMBLY_PRODUCT = "dot";
public const string ASSEMBLY_TITLE = "功能全面的实用工具 - 程序员的瑞士军刀"; public const string ASSEMBLY_TITLE = "功能全面的实用工具 - 程序员的瑞士军刀";
public const string ASSEMBLY_VERSION = _VERSION; public const string ASSEMBLY_VERSION = _VERSION;
private const string _VERSION = "1.1.6"; private const string _VERSION = "1.1.7";
} }

View File

@ -1,82 +0,0 @@
// ReSharper disable ClassNeverInstantiated.Global
#if NET7_0_WINDOWS
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Dot.Color;
internal sealed class MouseHook : IDisposable
{
private const int _WH_MOUSE_LL = 14;
private const int _WM_LBUTTONDOWN = 0x0201;
private const int _WM_MOUSEMOVE = 0x0200;
private readonly nint _hookId;
private bool _disposed;
public MouseHook()
{
_hookId = SetHook(HookCallback);
}
~MouseHook()
{
Dispose(false);
}
public event MouseEventHandler MouseEvent;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private static nint SetHook(Func<int, nint, nint, nint> proc)
{
using var curProcess = Process.GetCurrentProcess();
using var curModule = curProcess.MainModule!;
return Win32.SetWindowsHookEx(_WH_MOUSE_LL, proc, Win32.GetModuleHandle(curModule.ModuleName), 0);
}
private void Dispose(bool disposing)
{
if (_disposed) {
return;
}
if (disposing) {
//
}
if (_hookId != default) {
Win32.UnhookWindowsHookEx(_hookId);
}
_disposed = true;
}
private nint HookCallback(int nCode, nint wParam, nint lParam)
{
if (nCode < 0 || (wParam != _WM_MOUSEMOVE && wParam != _WM_LBUTTONDOWN)) {
return Win32.CallNextHookEx(_hookId, nCode, wParam, lParam);
}
var hookStruct = (Msllhookstruct)Marshal.PtrToStructure(lParam, typeof(Msllhookstruct))!;
MouseEvent?.Invoke(null, new MouseEventArgs( //
wParam == _WM_MOUSEMOVE ? MouseButtons.None : MouseButtons.Left //
, 0 //
, hookStruct.X //
, hookStruct.Y //
, 0));
return Win32.CallNextHookEx(_hookId, nCode, wParam, lParam);
}
[StructLayout(LayoutKind.Explicit)]
private readonly struct Msllhookstruct
{
[FieldOffset(0)] public readonly int X;
[FieldOffset(4)] public readonly int Y;
}
}
#endif

View File

@ -1,6 +1,7 @@
#if NET7_0_WINDOWS #if NET7_0_WINDOWS
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
using Dot.Native;
using TextCopy; using TextCopy;
namespace Dot.Color; namespace Dot.Color;

73
src/Native/MouseHook.cs Normal file
View File

@ -0,0 +1,73 @@
// ReSharper disable ClassNeverInstantiated.Global
#if NET7_0_WINDOWS
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Dot.Native;
internal sealed class MouseHook : IDisposable
{
private readonly nint _hookId;
private bool _disposed;
public MouseHook()
{
_hookId = SetHook(HookCallback);
}
~MouseHook()
{
Dispose(false);
}
public event MouseEventHandler MouseMoveEvent;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private static nint SetHook(Win32.HookProc lpfn)
{
using var process = Process.GetCurrentProcess();
using var module = process.MainModule;
return Win32.SetWindowsHookExA(Win32.WH_MOUSE_LL, lpfn, module!.BaseAddress, 0);
}
private void Dispose(bool disposing)
{
if (_disposed) {
return;
}
if (disposing) {
//
}
if (_hookId != default) {
Win32.UnhookWindowsHookExA(_hookId);
}
_disposed = true;
}
private nint HookCallback(int nCode, nint wParam, nint lParam)
{
if (wParam == Win32.WM_MOUSEMOVE) {
var hookStruct = (Msllhookstruct)Marshal.PtrToStructure(lParam, typeof(Msllhookstruct))!;
MouseMoveEvent?.Invoke(null, new MouseEventArgs(MouseButtons.None, 0, hookStruct.X, hookStruct.Y, 0));
}
return Win32.CallNextHookEx(_hookId, nCode, wParam, lParam);
}
[StructLayout(LayoutKind.Explicit)]
private readonly struct Msllhookstruct
{
[FieldOffset(0)] public readonly int X;
[FieldOffset(4)] public readonly int Y;
}
}
#endif

View File

@ -3,17 +3,23 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Dot; namespace Dot.Native;
internal static partial class Win32 internal static partial class Win32
{ {
public const int SW_HIDE = 0; public const int CS_DROP_SHADOW = 0x20000;
public const int WM_CHANGECBCHAIN = 0x030D; public const int GCL_STYLE = -26;
public const int WM_DRAWCLIPBOARD = 0x308; public const int SW_HIDE = 0;
public const int WH_MOUSE_LL = 14;
public const int WM_CHANGECBCHAIN = 0x030D;
public const int WM_DRAWCLIPBOARD = 0x308;
public const int WM_LBUTTONDOWN = 0x0201;
public const int WM_MOUSEMOVE = 0x0200;
private const string _GDI32_DLL = "gdi32.dll";
private const string _KERNEL32_DLL = "kernel32.dll";
private const string _USER32_DLL = "user32.dll";
private const string _GDI32_DLL = "gdi32.dll"; public delegate nint HookProc(int nCode, nint wParam, nint lParam);
private const string _KERNEL32_DLL = "kernel32.dll";
private const string _USER32_DLL = "user32.dll";
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial nint CallNextHookEx(nint hhk, int nCode, nint wParam, nint lParam); internal static partial nint CallNextHookEx(nint hhk, int nCode, nint wParam, nint lParam);
@ -22,6 +28,9 @@ internal static partial class Win32
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool ChangeClipboardChain(nint hWndRemove, nint hWndNewNext); internal static partial bool ChangeClipboardChain(nint hWndRemove, nint hWndNewNext);
[LibraryImport(_USER32_DLL)]
internal static partial int GetClassLongA(nint hWnd, int nIndex);
[LibraryImport(_KERNEL32_DLL)] [LibraryImport(_KERNEL32_DLL)]
internal static partial nint GetConsoleWindow(); internal static partial nint GetConsoleWindow();
@ -29,7 +38,7 @@ internal static partial class Win32
internal static partial nint GetDesktopWindow(); internal static partial nint GetDesktopWindow();
[LibraryImport(_KERNEL32_DLL, StringMarshalling = StringMarshalling.Utf16)] [LibraryImport(_KERNEL32_DLL, StringMarshalling = StringMarshalling.Utf16)]
internal static partial nint GetModuleHandle(string lpModuleName); internal static partial nint GetModuleHandleA(string lpModuleName);
[LibraryImport(_GDI32_DLL)] [LibraryImport(_GDI32_DLL)]
internal static partial uint GetPixel(nint dc, int x, int y); internal static partial uint GetPixel(nint dc, int x, int y);
@ -43,6 +52,9 @@ internal static partial class Win32
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial int SendMessageA(nint hwnd, uint wMsg, nint wParam, nint lParam); internal static partial int SendMessageA(nint hwnd, uint wMsg, nint wParam, nint lParam);
[LibraryImport(_USER32_DLL)]
internal static partial int SetClassLongA(nint hWnd, int nIndex, int dwNewLong);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial int SetClipboardViewer(nint hWnd); internal static partial int SetClipboardViewer(nint hWnd);
@ -50,8 +62,7 @@ internal static partial class Win32
internal static partial void SetLocalTime(Systemtime st); internal static partial void SetLocalTime(Systemtime st);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial nint SetWindowsHookEx(int idHook, Func<int, nint, nint, nint> lpfn, nint hMod internal static partial nint SetWindowsHookExA(int idHook, HookProc lpfn, nint hMod, uint dwThreadId);
, uint dwThreadId);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
@ -59,7 +70,7 @@ internal static partial class Win32
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool UnhookWindowsHookEx(nint hhk); internal static partial bool UnhookWindowsHookExA(nint hhk);
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
internal ref struct Systemtime internal ref struct Systemtime

View File

@ -1,22 +0,0 @@
namespace Dot.Text;
internal sealed partial class Main
{
private ref struct Output
{
public ReadOnlySpan<char> Base64;
public ReadOnlySpan<char> Base64DeCode;
public ReadOnlySpan<char> Base64DeCodeHex;
public ReadOnlySpan<char> EncodingName;
public ReadOnlySpan<char> Hex;
public ReadOnlySpan<char> HtmlDecode;
public ReadOnlySpan<char> HtmlEncode;
public ReadOnlySpan<char> Md5;
public ReadOnlySpan<char> OriginText;
public ReadOnlySpan<char> Sha1;
public ReadOnlySpan<char> Sha256;
public ReadOnlySpan<char> Sha512;
public ReadOnlySpan<char> UrlDecode;
public ReadOnlySpan<char> UrlEncode;
}
}

View File

@ -12,7 +12,7 @@ namespace Dot.Text;
[Description(nameof(Str.TextTool))] [Description(nameof(Str.TextTool))]
[Localization(typeof(Str))] [Localization(typeof(Str))]
internal sealed partial class Main : ToolBase<Option> internal sealed class Main : ToolBase<Option>
{ {
#if NET7_0_WINDOWS #if NET7_0_WINDOWS
protected override async Task Core() protected override async Task Core()
@ -39,20 +39,29 @@ internal sealed partial class Main : ToolBase<Option>
{ {
Output ret; Output ret;
var inputHex = text.Hex(enc); var inputHex = text.Hex(enc);
ret.Base64DeCodeHex = ReadOnlySpan<char>.Empty; ret.Base64DeCodeHex = ReadOnlySpan<char>.Empty;
ret.Base64DeCode = ReadOnlySpan<char>.Empty; ret.Base64DeCode = ReadOnlySpan<char>.Empty;
ret.EncodingName = enc.EncodingName; ret.EncodingName = enc.EncodingName;
ret.OriginText = text; ret.Hex = inputHex.String();
ret.Hex = inputHex.String(); ret.Base64 = text.Base64(enc);
ret.Base64 = text.Base64(enc); ret.Md5 = MD5.HashData(inputHex).String();
ret.Md5 = MD5.HashData(inputHex).String(); ret.Sha1 = SHA1.HashData(inputHex).String();
ret.Sha1 = SHA1.HashData(inputHex).String(); ret.Sha256 = SHA256.HashData(inputHex).String();
ret.Sha256 = SHA256.HashData(inputHex).String(); ret.Sha512 = SHA512.HashData(inputHex).String();
ret.Sha512 = SHA512.HashData(inputHex).String(); ret.UrlEncode = text.Url();
ret.UrlEncode = text.Url(); ret.UrlDecode = text.UrlDe();
ret.UrlDecode = text.UrlDe(); ret.HtmlDecode = text.HtmlDe();
ret.HtmlDecode = text.HtmlDe(); ret.HtmlEncode = text.Html();
ret.HtmlEncode = text.Html(); ret.PercentUnicode = default;
ret.AndUnicode = default;
ret.BacksLantUnicode = default;
ret.UnicodeDecode = text.UnicodeDe();
if (Equals(enc, Encoding.BigEndianUnicode)) {
ret.PercentUnicode = inputHex.String(false, "%u", 2);
ret.AndUnicode = inputHex.String(false, @";&#x", 2)[1..] + ";";
ret.BacksLantUnicode = inputHex.String(false, @"\u", 2);
}
if (!text.IsBase64String()) { if (!text.IsBase64String()) {
return ret; return ret;
@ -76,6 +85,37 @@ internal sealed partial class Main : ToolBase<Option>
return ret; return ret;
} }
private static string BuildTemplate(Output o)
{
var sb = new StringBuilder();
sb.AppendLine( //
CultureInfo.InvariantCulture
, $"{new string('-', 20)} {o.EncodingName} {new string('-', 30 - o.EncodingName.Length)}");
sb.AppendLine(CultureInfo.InvariantCulture, $"hex: {o.Hex}");
sb.AppendLine(CultureInfo.InvariantCulture, $"base64: {o.Base64}");
sb.AppendLine(CultureInfo.InvariantCulture, $"base64-decode-hex: {o.Base64DeCodeHex}");
sb.AppendLine(CultureInfo.InvariantCulture, $"base64-decode: {o.Base64DeCode}");
sb.AppendLine(CultureInfo.InvariantCulture, $"md5: {o.Md5}");
sb.AppendLine(CultureInfo.InvariantCulture, $"sha1: {o.Sha1}");
sb.AppendLine(CultureInfo.InvariantCulture, $"sha256: {o.Sha256}");
sb.AppendLine(CultureInfo.InvariantCulture, $"sha512: {o.Sha512}");
sb.AppendLine(CultureInfo.InvariantCulture, $"url-encode: {o.UrlEncode}");
sb.AppendLine(CultureInfo.InvariantCulture, $"url-decode: {o.UrlDecode}");
if (o.EncodingName.Equals(Encoding.BigEndianUnicode.EncodingName, StringComparison.OrdinalIgnoreCase)) {
sb.AppendLine(CultureInfo.InvariantCulture, $"unicode-percent: {o.PercentUnicode}");
sb.AppendLine(CultureInfo.InvariantCulture, $"unicode-and: {o.AndUnicode}");
sb.AppendLine(CultureInfo.InvariantCulture, $"unicode-backslant: {o.BacksLantUnicode}");
sb.AppendLine(CultureInfo.InvariantCulture, $"unicode-decode: {o.UnicodeDecode}");
}
sb.AppendLine(CultureInfo.InvariantCulture, $"html-encode: {o.HtmlEncode}");
sb.AppendLine(CultureInfo.InvariantCulture, $"html-decode: {o.HtmlDecode}");
return sb.ToString();
}
private static void ParseAndShow(string text) private static void ParseAndShow(string text)
{ {
var ansi = BuildOutput(text, Encoding.GetEncoding("gbk")); var ansi = BuildOutput(text, Encoding.GetEncoding("gbk"));
@ -83,35 +123,40 @@ internal sealed partial class Main : ToolBase<Option>
var unicodeLittleEndian = BuildOutput(text, Encoding.Unicode); var unicodeLittleEndian = BuildOutput(text, Encoding.Unicode);
var unicodeBigEndian = BuildOutput(text, Encoding.BigEndianUnicode); var unicodeBigEndian = BuildOutput(text, Encoding.BigEndianUnicode);
PrintOutput(ansi); var sb = new StringBuilder();
PrintOutput(utf8); sb.AppendLine(BuildTemplate(ansi));
PrintOutput(unicodeLittleEndian); sb.AppendLine(BuildTemplate(utf8));
PrintOutput(unicodeBigEndian); sb.AppendLine(BuildTemplate(unicodeLittleEndian));
} sb.AppendLine(BuildTemplate(unicodeBigEndian));
var str = sb.ToString();
Console.WriteLine(str);
private static void PrintOutput(Output o)
{
var outputTemp = $"""
origin-text: {o.OriginText}
{new string('-', 20)} {o.EncodingName} {new string('-', 30 - o.EncodingName.Length)}
hex: {o.Hex}
base64: {o.Base64}
base64-decode-hex: {o.Base64DeCodeHex}
base64-decode: {o.Base64DeCode}
md5: {o.Md5}
sha1: {o.Sha1}
sha256: {o.Sha256}
sha512: {o.Sha512}
url-encode: {o.UrlEncode}
url-decode: {o.UrlDecode}
html-encode: {o.HtmlEncode}
html-decode: {o.HtmlDecode}
""";
Console.WriteLine(outputTemp);
#if NET7_0_WINDOWS #if NET7_0_WINDOWS
var file = Path.Combine(Path.GetTempPath(), $"{System.Guid.NewGuid()}.html"); var file = Path.Combine(Path.GetTempPath(), $"{System.Guid.NewGuid()}.txt");
File.WriteAllText(file, outputTemp.Text2Html()); File.WriteAllText(file, str);
Process.Start("explorer", file); Process.Start("explorer", file);
#endif #endif
} }
private ref struct Output
{
public ReadOnlySpan<char> AndUnicode;
public ReadOnlySpan<char> BacksLantUnicode;
public ReadOnlySpan<char> Base64;
public ReadOnlySpan<char> Base64DeCode;
public ReadOnlySpan<char> Base64DeCodeHex;
public ReadOnlySpan<char> EncodingName;
public ReadOnlySpan<char> Hex;
public ReadOnlySpan<char> HtmlDecode;
public ReadOnlySpan<char> HtmlEncode;
public ReadOnlySpan<char> Md5;
public ReadOnlySpan<char> PercentUnicode;
public ReadOnlySpan<char> Sha1;
public ReadOnlySpan<char> Sha256;
public ReadOnlySpan<char> Sha512;
public ReadOnlySpan<char> UnicodeDecode;
public ReadOnlySpan<char> UrlDecode;
public ReadOnlySpan<char> UrlEncode;
}
} }

View File

@ -1,6 +1,7 @@
// ReSharper disable ClassNeverInstantiated.Global // ReSharper disable ClassNeverInstantiated.Global
using System.Net.Sockets; using System.Net.Sockets;
using Dot.Native;
namespace Dot.Time; namespace Dot.Time;

View File

@ -0,0 +1,60 @@
using NSExt.Extensions;
namespace Dot.Tran;
internal static class BaiduSignCracker
{
private const int _MAGIC_NUMBER_1 = 320305;
private const int _MAGIC_NUMBER_2 = 131321201;
public static string Sign(string text)
{
var e = new List<int>(text.Length);
for (var i = 0; i < text.Length; i++) {
var k = (int)text[i];
switch (k) {
case < 128:
e.Add(k);
break;
case < 2048:
e.Add((k >> 6) | 192);
break;
default: {
if ((k & 64512) == 55296 && i + 1 < text.Length && (text[i + 1] & 64512) == 56320) {
k = 65536 + ((k & 1023) << 10) + (text[++i] & 1023);
e.Add((k >> 18) | 240);
e.Add(((k >> 12) & 63) | 128);
}
else {
e.Add((k >> 12) | 224);
e.Add(((k >> 6) & 63) | 128);
e.Add((k & 63) | 128);
}
break;
}
}
}
var ret = e.Aggregate(_MAGIC_NUMBER_1, (accumulator, source) => Compute(accumulator + source, "+-a^+6"));
ret = Compute(ret, "+-3^+b+-f");
ret ^= _MAGIC_NUMBER_2;
var longRet = ret < 0 ? 1L + (ret & int.MaxValue) + int.MaxValue : ret;
longRet %= 1_000_000;
return $"{longRet}.{longRet ^ _MAGIC_NUMBER_1}";
}
private static int Compute(int number, string password)
{
unchecked {
for (var i = 0; i < password.Length - 2; i += 3) {
var c = password[i + 2];
var moveBit = c >= 'a' ? c - 87 : c.ToString().Int32();
var d = password[i + 1] == '+' ? number >>> moveBit : number << moveBit;
number = password[i] == '+' ? (number + d) & (int)uint.MaxValue : number ^ d;
}
}
return number;
}
}

View File

@ -0,0 +1,62 @@
// ReSharper disable InconsistentNaming
// ReSharper disable ClassNeverInstantiated.Global
#pragma warning disable IDE1006,SA1300
namespace Dot.Tran.Dto;
internal sealed record BaiduTranslateResultDto
{
public sealed record DataItem
{
public string dst { get; set; }
public int prefixWrap { get; set; }
public string result { get; set; }
public string src { get; set; }
}
public sealed record PhoneticItem
{
public string src_str { get; set; }
public string trg_str { get; set; }
}
public sealed record Root
{
public string errmsg { get; set; }
public int errno { get; set; }
public int error { get; set; }
public string errShowMsg { get; set; }
public string from { get; set; }
public long logid { get; set; }
public string query { get; set; }
public string to { get; set; }
public Trans_result trans_result { get; set; }
}
public sealed record Trans_result
{
public List<DataItem> data { get; set; }
public string from { get; set; }
public List<PhoneticItem> phonetic { get; set; }
public int status { get; set; }
public string to { get; set; }
public int type { get; set; }
}
}

View File

@ -1,37 +1,38 @@
#if NET7_0_WINDOWS #if NET7_0_WINDOWS
using System.Net;
using System.Text.RegularExpressions;
using Dot.Native;
using Dot.Tran.Dto;
using NSExt.Extensions; using NSExt.Extensions;
using Colors = System.Drawing.Color; using TextCopy;
using Padding = System.Windows.Forms.Padding;
using Size = System.Drawing.Size; using Size = System.Drawing.Size;
namespace Dot.Tran; namespace Dot.Tran;
internal sealed class FrmMain : Form internal sealed partial class FrmMain : Form
{ {
private const int _HIDING_MIL_SECS = 1000; // 鼠标离开超过此时间后隐藏窗体 private const int _HIDING_MIL_SECS = 5000; // 隐藏窗体时间(秒
private const string _TOKEN_URL = "https://fanyi.qq.com/api/reauth12f"; private const int _RETRY_WAIT_MIL_SEC = 1000; // 重试等待时间(秒)
private const string _URL = "https://fanyi.qq.com/api/translate"; private const string _TRANSLATE_API_URL = "https://fanyi.baidu.com/v2transapi";
private static ManualResetEvent _mre = new(false); // 隐藏窗体侦测线程信号 private const string _TRANSLATE_HOME_URL = "https://fanyi.baidu.com";
private const double _WINDOW_OPACITY = .5; // 窗体透明度
private static ManualResetEvent _mre = new(false); // 隐藏窗体侦测线程信号
private readonly HttpClient _httpClient = new();
private readonly Label _labelDest = new(); // 显示翻译内容的文本框
private readonly Colors _bgColor // 背景颜色 private readonly MouseHook _mouseHook = new();
= Colors.FromArgb(0xff, 0x1e, 0x1e, 0x1e); private readonly Size _mouseMargin = new(10, 10);
private bool _disposed;
private readonly Colors _foreColor = Colors.White; // 字体颜色 private DateTime? _latestActiveTime; // 窗体最后激活时间
private nint _nextHwnd; // 下一个剪贴板监视链对象句柄
private readonly HttpClient _httpClient = new(); private string _token = "ae72ebad4113270fd26ada5125301268";
private readonly RichTextBox _richTextSource = new(); // 显示剪贴板内容的富文本框
private readonly TextBox _textDest = new(); // 显示翻译内容的文本框
private readonly Padding _windowPadding = new(10, 10, 10, 10); // 窗体边距
private readonly Size _windowSize = new(640, 360); // 窗体大小
private DateTime? _mouseLeaveTime; // 鼠标离开窗体时间
private nint _nextHwnd; // 下一个剪贴板监视链对象句柄
public FrmMain() public FrmMain()
{ {
InitForm(); InitForm();
InitHook();
InitTextSource(); InitLabelDest();
InitTextDest(); InitHttpClient();
_nextHwnd = Win32.SetClipboardViewer(Handle); _nextHwnd = Win32.SetClipboardViewer(Handle);
@ -40,35 +41,27 @@ internal sealed class FrmMain : Form
~FrmMain() ~FrmMain()
{ {
_mre?.Dispose(); Dispose(false);
_richTextSource?.Dispose();
} }
protected override void OnClosed(EventArgs e) protected override void Dispose(bool disposing)
{ {
base.OnClosed(e); base.Dispose(disposing);
// 结束定时隐藏窗体线程 if (_disposed) {
_mre = null;
// 从剪贴板监视链移除本窗体
Win32.ChangeClipboardChain(Handle, _nextHwnd);
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
_mouseLeaveTime = null;
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
if (ClientRectangle.Contains(PointToClient(MousePosition))) {
return; return;
} }
_mouseLeaveTime = DateTime.Now; if (disposing) {
_mre = null; // 结束定时隐藏窗体线程
_mre?.Dispose();
_httpClient?.Dispose();
_labelDest?.Dispose();
_mouseHook?.Dispose();
}
Win32.ChangeClipboardChain(Handle, _nextHwnd); // 从剪贴板监视链移除本窗体
_disposed = true;
} }
protected override void WndProc(ref Message m) protected override void WndProc(ref Message m)
@ -84,6 +77,7 @@ internal sealed class FrmMain : Form
SendToNext(m); SendToNext(m);
break; break;
case Win32.WM_CHANGECBCHAIN: case Win32.WM_CHANGECBCHAIN:
Console.WriteLine(Win32.WM_CHANGECBCHAIN);
if (m.WParam == _nextHwnd) { if (m.WParam == _nextHwnd) {
_nextHwnd = m.LParam; _nextHwnd = m.LParam;
} }
@ -98,61 +92,44 @@ internal sealed class FrmMain : Form
} }
} }
[GeneratedRegex("token: '(\\w+)'")]
private static partial Regex MyRegex();
/// <summary> /// <summary>
/// 显示剪贴板内容. /// 显示剪贴板内容.
/// </summary> /// </summary>
private void DisplayClipboardData() private void DisplayClipboardData()
{ {
var clipData = Clipboard.GetDataObject(); var clipText = ClipboardService.GetText();
if (clipData is null) { if (clipText.NullOrWhiteSpace()) {
return; return;
} }
if (clipData.GetDataPresent(DataFormats.Rtf)) { _labelDest.Text = Str.Translating;
_richTextSource.Rtf = clipData.GetData(DataFormats.Rtf) as string; Task.Run(() => {
} var translateText = _labelDest.Text = TranslateText(clipText);
else if (clipData.GetDataPresent(DataFormats.Text)) { Invoke(() => { _labelDest.Text = translateText; });
_richTextSource.Text = clipData.GetData(DataFormats.Text) as string; });
}
else {
return;
}
var mousePos = Cursor.Position; var point = Cursor.Position;
mousePos.Offset(-_windowPadding.Left, -_windowPadding.Top); point.Offset(new Point(_mouseMargin));
Location = mousePos; Location = point;
Visible = true; Show();
_mouseLeaveTime = null; _latestActiveTime = DateTime.Now;
_mre.Set(); _mre.Set();
} }
private TokenStruct GetTranslateToken()
{
using var rsp = _httpClient.PostAsync(_TOKEN_URL, new StringContent(string.Empty)).Result;
var rspStr = rsp.Content.ReadAsStringAsync().Result;
return rspStr.Object<TokenStruct>();
}
private int HalfHeight()
{
return (_windowSize.Height - _windowPadding.Top - _windowPadding.Bottom) / 2 - _windowPadding.Top / 2;
}
private async Task HideWindow() private async Task HideWindow()
{ {
while (_mre is not null) { while (_mre is not null) {
while (Visible) { while (Visible) {
await Task.Delay(100); await Task.Delay(100);
if (_mouseLeaveTime is null || if (_latestActiveTime is null ||
!((DateTime.Now - _mouseLeaveTime.Value).TotalMilliseconds > _HIDING_MIL_SECS)) { !((DateTime.Now - _latestActiveTime.Value).TotalMilliseconds > _HIDING_MIL_SECS)) {
continue; continue;
} }
Invoke(() => { Invoke(Hide);
Visible = false;
_richTextSource.Clear();
_textDest.Clear();
});
} }
_mre.WaitOne(); _mre.WaitOne();
@ -161,73 +138,74 @@ internal sealed class FrmMain : Form
private void InitForm() private void InitForm()
{ {
BackColor = _bgColor; AutoSize = true;
AutoSizeMode = AutoSizeMode.GrowAndShrink;
FormBorderStyle = FormBorderStyle.None; FormBorderStyle = FormBorderStyle.None;
Padding = _windowPadding; Opacity = _WINDOW_OPACITY;
Size = _windowSize;
TopMost = true; TopMost = true;
Visible = false; Visible = false;
} }
private void InitTextDest() private void InitHook()
{ {
_textDest.BackColor = _bgColor; _mouseHook.MouseMoveEvent += (_, e) => {
_textDest.BorderStyle = BorderStyle.None; var point = new Point(e.X, e.Y);
_textDest.Dock = DockStyle.Bottom; point.Offset(new Point(_mouseMargin));
_textDest.ForeColor = _foreColor; Location = point;
_textDest.Height = HalfHeight(); };
_textDest.Margin = new Padding(0, _windowPadding.Top / 2, 0, 0);
_textDest.MouseEnter += (_, e) => OnMouseEnter(e);
_textDest.Multiline = true;
_textDest.ScrollBars = ScrollBars.None;
Controls.Add(_textDest);
} }
private void InitTextSource() private void InitHttpClient()
{ {
_richTextSource.TextChanged += (sender, e) => { _httpClient.DefaultRequestHeaders.Add( //
if (_richTextSource.Text.NullOrWhiteSpace()) { "User-Agent"
return; , " Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36");
} }
_textDest.Text = Str.Translating; private void InitLabelDest()
_textDest.Text = TranslateText(_richTextSource.Text); {
}; _labelDest.BorderStyle = BorderStyle.None;
_richTextSource.BackColor = _bgColor; _labelDest.Dock = DockStyle.Fill;
_richTextSource.BorderStyle = BorderStyle.None; _labelDest.AutoSize = true;
_richTextSource.Dock = DockStyle.Top; Controls.Add(_labelDest);
_richTextSource.ForeColor = _foreColor;
_richTextSource.Height = HalfHeight();
_richTextSource.Margin = new Padding(0, 0, 0, _windowPadding.Top / 2);
_richTextSource.MouseEnter += (_, e) => OnMouseEnter(e);
_richTextSource.ScrollBars = RichTextBoxScrollBars.None;
Controls.Add(_richTextSource);
} }
private string TranslateText(string sourceText) private string TranslateText(string sourceText)
{ {
var token = GetTranslateToken(); while (true) {
var content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>> { var hash = sourceText.Length > 30
new("source", "auto") ? string.Concat(sourceText.AsSpan()[..10], sourceText.AsSpan(sourceText.Length / 2 - 5, 10)
, new("target", "zh") , sourceText.AsSpan()[^10..])
, new("qtv", token.Qtv.Url()) : sourceText;
, new("qtk", token.Qtk.Url()) var sign = BaiduSignCracker.Sign(hash);
, new("sourceText", sourceText.Url()) var content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>> {
}); new("from", "auto")
var rsp = _httpClient.PostAsync(_URL, content).Result; , new("to", "zh")
var ret = rsp.Content.ReadAsStringAsync().Result; , new("query", sourceText)
, new("simple_means_flag", "3")
, new("sign", sign)
, new("token", _token)
, new("domain", "common")
});
return ret; var rsp = _httpClient.PostAsync(_TRANSLATE_API_URL, content).Result;
} var rspObj = rsp.Content.ReadAsStringAsync().Result.Object<BaiduTranslateResultDto.Root>();
if (rspObj.error == 0) {
return string.Join(Environment.NewLine, rspObj.trans_result.data.Select(x => x.dst));
}
private readonly struct TokenStruct Console.Error.WriteLine(rspObj.Json().UnicodeDe());
{ Console.Error.WriteLine(rsp.Headers.Json());
// ReSharper disable UnusedAutoPropertyAccessor.Local
public string Qtk { get; init; }
public string Qtv { get; init; } //cookie or token invalid
Task.Delay(_RETRY_WAIT_MIL_SEC).Wait();
// ReSharper restore UnusedAutoPropertyAccessor.Local var cookie = string.Join(
';', rsp.Headers.First(x => x.Key == "Set-Cookie").Value.Select(x => x.Split(';').First()));
_httpClient.DefaultRequestHeaders.Remove(nameof(Cookie));
_httpClient.DefaultRequestHeaders.Add(nameof(Cookie), cookie);
var html = _httpClient.GetStringAsync(_TRANSLATE_HOME_URL).Result;
_token = MyRegex().Match(html).Groups[1].Value;
}
} }
} }
#endif #endif

View File

@ -9,7 +9,10 @@ internal sealed class Main : ToolBase<Option>
[SupportedOSPlatform(nameof(OSPlatform.Windows))] [SupportedOSPlatform(nameof(OSPlatform.Windows))]
protected override Task Core() protected override Task Core()
{ {
var th = new Thread(() => { Application.Run(new FrmMain()); }); var th = new Thread(() => {
using var frm = new FrmMain();
Application.Run(frm);
});
th.SetApartmentState(ApartmentState.STA); th.SetApartmentState(ApartmentState.STA);
th.Start(); th.Start();
th.Join(); th.Join();

View File

@ -13,7 +13,7 @@
<DefineConstants>$(DefineConstants);NET7_0_WINDOWS</DefineConstants> <DefineConstants>$(DefineConstants);NET7_0_WINDOWS</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="NSExt" Version="1.0.9-alpha.0.1" /> <PackageReference Include="NSExt" Version="1.0.11-alpha.0.1" />
<PackageReference Include="Spectre.Console.Cli.NS" Version="0.45.1-preview.0.48" /> <PackageReference Include="Spectre.Console.Cli.NS" Version="0.45.1-preview.0.48" />
<PackageReference Include="Spectre.Console.NS" Version="0.45.1-preview.0.48" /> <PackageReference Include="Spectre.Console.NS" Version="0.45.1-preview.0.48" />
<PackageReference Condition="'$(TargetFramework)' == 'net7.0-windows'" Include="TextCopy" Version="6.2.0" /> <PackageReference Condition="'$(TargetFramework)' == 'net7.0-windows'" Include="TextCopy" Version="6.2.0" />

View File

@ -11,7 +11,7 @@
"packages": [ "packages": [
{ {
"packageName": "NSExt", "packageName": "NSExt",
"version": "1.0.9-alpha.0.1" "version": "1.0.11-alpha.0.1"
}, },
{ {
"packageName": "Spectre.Console.Cli.NS", "packageName": "Spectre.Console.Cli.NS",