Merge branch 'dev' into tk

This commit is contained in:
nsnail 2022-12-21 10:01:24 +08:00
commit bd2f88a1d6
9 changed files with 388 additions and 66 deletions

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.1";
} }

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root" xmlns="">
id="root" xmlns="">
<xsd:element name="root" msdata:IsDataSet="true"></xsd:element> <xsd:element name="root" msdata:IsDataSet="true"></xsd:element>
</xsd:schema> </xsd:schema>
<resheader name="resmimetype"> <resheader name="resmimetype">
@ -254,4 +253,16 @@
<data name="BufferSize" xml:space="preserve"> <data name="BufferSize" xml:space="preserve">
<value>Buffer size (kilobytes)</value> <value>Buffer size (kilobytes)</value>
</data> </data>
<data name="Translating" xml:space="preserve">
<value>In translation...</value>
</data>
<data name="HideTranslate" xml:space="preserve">
<value>Press [green] Esc[/] to hide the translation</value>
</data>
<data name="StartTranslate" xml:space="preserve">
<value>Select the text and press [green] Capslock[/] to start the translation</value>
</data>
<data name="TranslateTool" xml:space="preserve">
<value>Translation tools</value>
</data>
</root> </root>

View File

@ -267,4 +267,13 @@
<data name="Translating" xml:space="preserve"> <data name="Translating" xml:space="preserve">
<value>翻译中...</value> <value>翻译中...</value>
</data> </data>
<data name="HideTranslate" xml:space="preserve">
<value>按下 [green]Esc[/] 隐藏译文</value>
</data>
<data name="StartTranslate" xml:space="preserve">
<value>选中文本按下 [green]Capslock[/] 开始翻译</value>
</data>
<data name="TranslateTool" xml:space="preserve">
<value>翻译工具</value>
</data>
</root> </root>

View File

@ -0,0 +1,71 @@
// ReSharper disable ClassNeverInstantiated.Global
#if NET7_0_WINDOWS
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Dot.Native;
internal sealed class KeyboardHook : IDisposable
{
private readonly nint _hookId;
private bool _disposed;
public KeyboardHook()
{
_hookId = SetHook(HookCallback);
}
~KeyboardHook()
{
Dispose(false);
}
public delegate bool KeyUpEventHandler(object sender, Win32.KbdllhooksStruct e);
public KeyUpEventHandler KeyUpEvent { get; set; }
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_KEYBOARD_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 (nCode >= 0 && wParam == Win32.WM_KEYDOWN) {
var hookStruct = (Win32.KbdllhooksStruct)Marshal.PtrToStructure(lParam, typeof(Win32.KbdllhooksStruct))!;
if (KeyUpEvent?.Invoke(null, hookStruct) ?? false) {
return -1;
}
}
return Win32.CallNextHookEx(_hookId, nCode, wParam, lParam);
}
}
#endif

172
src/Native/VkCode.cs Normal file
View File

@ -0,0 +1,172 @@
#pragma warning disable CS1591
namespace Dot.Native;
public class VkCode
{
public const int VK_A = 0x41; // A 键
public const int VK_ACCEPT = 0x1E; // IME 接受
public const int VK_ADD = 0x6B; // 添加密钥
public const int VK_APPS = 0x5D; // 应用程序键 (自然键盘)
public const int VK_ATTN = 0xF6; // Attn 键
public const int VK_B = 0x42; // B 键
public const int VK_BACK = 0x08; // BACKSPACE 密钥
public const int VK_BROWSER_BACK = 0xA6; // 浏览器后退键
public const int VK_BROWSER_FAVORITES = 0xAB; // 浏览器收藏键
public const int VK_BROWSER_FORWARD = 0xA7; // 浏览器前进键
public const int VK_BROWSER_HOME = 0xAC; // 浏览器“开始”和“主页”键
public const int VK_BROWSER_REFRESH = 0xA8; // 浏览器刷新键
public const int VK_BROWSER_SEARCH = 0xAA; // 浏览器搜索键
public const int VK_BROWSER_STOP = 0xA9; // 浏览器停止键
public const int VK_C = 0x43; // C 键
public const int VK_CANCEL = 0x03; // 控制中断处理
public const int VK_CAPITAL = 0x14; // CAPS LOCK 键
public const int VK_CLEAR = 0x0C; // CLEAR 键
public const int VK_CONTROL = 0x11; // Ctrl 键
public const int VK_CONVERT = 0x1C; // IME 转换
public const int VK_CRSEL = 0xF7; // CrSel 键
public const int VK_D = 0x44; // D 键
public const int VK_DECIMAL = 0x6E; // 十进制键
public const int VK_DELETE = 0x2E; // DEL 键
public const int VK_DIVIDE = 0x6F; // 除键
public const int VK_DOWN = 0x28; // 向下键
public const int VK_E = 0x45; // E 键
public const int VK_END = 0x23; // END 键
public const int VK_EREOF = 0xF9; // 擦除 EOF 密钥
public const int VK_ESCAPE = 0x1B; // ESC 键
public const int VK_EXECUTE = 0x2B; // EXECUTE 键
public const int VK_EXSEL = 0xF8; // ExSel 密钥
public const int VK_F = 0x46; // F 键
public const int VK_F1 = 0x70; // F1 键
public const int VK_F10 = 0x79; // F10 键
public const int VK_F11 = 0x7A; // F11 键
public const int VK_F12 = 0x7B; // F12 键
public const int VK_F13 = 0x7C; // F13 键
public const int VK_F14 = 0x7D; // F14 键
public const int VK_F15 = 0x7E; // F15 键
public const int VK_F16 = 0x7F; // F16 键
public const int VK_F17 = 0x80; // F17 键
public const int VK_F18 = 0x81; // F18 键
public const int VK_F19 = 0x82; // F19 键
public const int VK_F2 = 0x71; // F2 键
public const int VK_F20 = 0x83; // F20 键
public const int VK_F21 = 0x84; // F21 键
public const int VK_F22 = 0x85; // F22 键
public const int VK_F23 = 0x86; // F23 键
public const int VK_F24 = 0x87; // F24 键
public const int VK_F3 = 0x72; // F3 键
public const int VK_F4 = 0x73; // F4 键
public const int VK_F5 = 0x74; // F5 键
public const int VK_F6 = 0x75; // F6 键
public const int VK_F7 = 0x76; // F7 键
public const int VK_F8 = 0x77; // F8 键
public const int VK_F9 = 0x78; // F9 键
public const int VK_FINAL = 0x18; // IME 最终模式
public const int VK_G = 0x47; // G 键
public const int VK_H = 0x48; // H 键
public const int VK_HANGUEL = 0x15; // IME 朝鲜文库埃尔模式 (保持兼容性;使用 VK_HANGUL)
public const int VK_HANGUL = 0x15; // IME Hanguel 模式
public const int VK_HANJA = 0x19; // IME Hanja 模式
public const int VK_HELP = 0x2F; // 帮助密钥
public const int VK_HOME = 0x24; // HOME 键
public const int VK_I = 0x49; // I 键
public const int VK_IME_OFF = 0x1A; // IME 关闭
public const int VK_IME_ON = 0x16; // IME On
public const int VK_INSERT = 0x2D; // INS 密钥
public const int VK_J = 0x4A; // J 键
public const int VK_JUNJA = 0x17; // IME Junja 模式
public const int VK_K = 0x4B; // K 键
public const int VK_KANA = 0x15; // IME Kana 模式
public const int VK_KANJI = 0x19; // IME Kanji 模式
public const int VK_L = 0x4C; // L 键
public const int VK_LAUNCH_APP1 = 0xB6; // 启动应用程序 1 键
public const int VK_LAUNCH_APP2 = 0xB7; // 启动应用程序 2 键
public const int VK_LAUNCH_MAIL = 0xB4; // 启动邮件键
public const int VK_LAUNCH_MEDIA_SELECT = 0xB5; // 选择媒体键
public const int VK_LBUTTON = 0x01; // 鼠标左键
public const int VK_LCONTROL = 0xA2; // 左 Ctrl 键
public const int VK_LEFT = 0x25; // 向左键
public const int VK_LMENU = 0xA4; // 左 Alt 键
public const int VK_LSHIFT = 0xA0; // 左 SHIFT 键
public const int VK_LWIN = 0x5B; // 左Windows键 (自然键盘)
public const int VK_M = 0x4D; // M 键
public const int VK_MBUTTON = 0x04; // 中间鼠标按钮 (三键鼠标)
public const int VK_MEDIA_NEXT_TRACK = 0xB0; // 下一曲目键
public const int VK_MEDIA_PLAY_PAUSE = 0xB3; // 播放/暂停媒体键
public const int VK_MEDIA_PREV_TRACK = 0xB1; // 上一曲目键
public const int VK_MEDIA_STOP = 0xB2; // 停止媒体键
public const int VK_MENU = 0x12; // Alt 键
public const int VK_MODECHANGE = 0x1F; // IME 模式更改请求
public const int VK_MULTIPLY = 0x6A; // 乘键
public const int VK_N = 0x4E; // N 键
public const int VK_NEXT = 0x22; // PAGE DOWN 键
public const int VK_NONAME = 0xFC; // 预留
public const int VK_NONCONVERT = 0x1D; // IME 不转换
public const int VK_NUMLOCK = 0x90; // NUM LOCK 密钥
public const int VK_NUMPAD0 = 0x60; // 数字键盘 0 键
public const int VK_NUMPAD1 = 0x61; // 数字键盘 1 键
public const int VK_NUMPAD2 = 0x62; // 数字键盘 2 键
public const int VK_NUMPAD3 = 0x63; // 数字键盘 3 键
public const int VK_NUMPAD4 = 0x64; // 数字键盘 4 键
public const int VK_NUMPAD5 = 0x65; // 数字键盘 5 键
public const int VK_NUMPAD6 = 0x66; // 数字键盘 6 键
public const int VK_NUMPAD7 = 0x67; // 数字键盘 7 键
public const int VK_NUMPAD8 = 0x68; // 数字键盘 8 键
public const int VK_NUMPAD9 = 0x69; // 数字键盘 9 键
public const int VK_O = 0x4F; // O 键
public const int VK_OEM_1 = 0xBA; // 用于其他字符;它可能因键盘而异。 对于美国标准键盘,“;:”键
public const int VK_OEM_102 = 0xE2; // <>美国标准键盘上的键,或\\|非美国 102 键键盘上的键
public const int VK_OEM_2 = 0xBF; // 用于其他字符;它可能因键盘而异。 对于美国标准键盘,“/?” key
public const int VK_OEM_3 = 0xC0; // 用于其他字符;它可能因键盘而异。 对于美国标准键盘,“~”键
public const int VK_OEM_4 = 0xDB; // 用于其他字符;它可能因键盘而异。 对于美国标准键盘,“[{”键
public const int VK_OEM_5 = 0xDC; // 用于其他字符;它可能因键盘而异。 对于美国标准键盘,“\|”键
public const int VK_OEM_6 = 0xDD; // 用于其他字符;它可能因键盘而异。 对于美国标准键盘,“]}”键
public const int VK_OEM_7 = 0xDE; // 用于其他字符;它可能因键盘而异。 对于美国标准键盘,“单引号/双引号”键
public const int VK_OEM_8 = 0xDF; // 用于其他字符;它可能因键盘而异。
public const int VK_OEM_CLEAR = 0xFE; // 清除键
public const int VK_OEM_COMMA = 0xBC; // 对于任何国家/地区,“,键
public const int VK_OEM_MINUS = 0xBD; // 对于任何国家/地区,“-”键
public const int VK_OEM_PERIOD = 0xBE; // 对于任何国家/地区,“.”键
public const int VK_OEM_PLUS = 0xBB; // 对于任何国家/地区,“+”键
public const int VK_P = 0x50; // P 键
public const int VK_PA1 = 0xFD; // PA1 键
public const int VK_PACKET = 0xE7; // 用于将 Unicode 字符当作键击传递。
public const int VK_PAUSE = 0x13; // PAUSE 键
public const int VK_PLAY = 0xFA; // 播放键
public const int VK_PRINT = 0x2A; // PRINT 键
public const int VK_PRIOR = 0x21; // PAGE UP 键
public const int VK_PROCESSKEY = 0xE5; // IME PROCESS 密钥
public const int VK_Q = 0x51; // Q 键
public const int VK_R = 0x52; // R 键
public const int VK_RBUTTON = 0x02; // 鼠标右键
public const int VK_RCONTROL = 0xA3; // 右 Ctrl 键
public const int VK_RETURN = 0x0D; // Enter 键
public const int VK_RIGHT = 0x27; // 向右键
public const int VK_RMENU = 0xA5; // 右 ALT 键
public const int VK_RSHIFT = 0xA1; // 右 SHIFT 键
public const int VK_RWIN = 0x5C; // 右Windows键 (自然键盘)
public const int VK_S = 0x53; // S 键
public const int VK_SCROLL = 0x91; // SCROLL LOCK 键
public const int VK_SELECT = 0x29; // SELECT 键
public const int VK_SEPARATOR = 0x6C; // 分隔符键
public const int VK_SHIFT = 0x10; // SHIFT 键
public const int VK_SLEEP = 0x5F; // 计算机休眠键
public const int VK_SNAPSHOT = 0x2C; // 打印屏幕键
public const int VK_SPACE = 0x20; // 空格键
public const int VK_SUBTRACT = 0x6D; // 减去键
public const int VK_T = 0x54; // T 键
public const int VK_TAB = 0x09; // Tab 键
public const int VK_U = 0x55; // U 键
public const int VK_UP = 0x26; // 向上键
public const int VK_V = 0x56; // V 键
public const int VK_VOLUME_DOWN = 0xAE; // 音量减小键
public const int VK_VOLUME_MUTE = 0xAD; // 静音键
public const int VK_VOLUME_UP = 0xAF; // 音量增加键
public const int VK_W = 0x57; // W 键
public const int VK_X = 0x58; // X 键
public const int VK_XBUTTON1 = 0x05; // X1 鼠标按钮
public const int VK_XBUTTON2 = 0x06; // X2 鼠标按钮
public const int VK_Y = 0x59; // Y 键
public const int VK_Z = 0x5A; // Z 键
public const int VK_ZOOM = 0xFB; // 缩放键
}

View File

@ -1,6 +1,8 @@
// ReSharper disable UnusedMember.Global // ReSharper disable UnusedMember.Global
// ReSharper disable UnusedMethodReturnValue.Global // ReSharper disable UnusedMethodReturnValue.Global
#pragma warning disable SA1307
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Dot.Native; namespace Dot.Native;
@ -9,10 +11,16 @@ internal static partial class Win32
{ {
public const int CS_DROP_SHADOW = 0x20000; public const int CS_DROP_SHADOW = 0x20000;
public const int GCL_STYLE = -26; public const int GCL_STYLE = -26;
public const int HC_ACTION = 0;
public const int INPUT_KEYBOARD = 1;
public const int KEYEVENTF_KEYUP = 0x0002;
public const int SW_HIDE = 0; public const int SW_HIDE = 0;
public const int WH_KEYBOARD_LL = 13;
public const int WH_MOUSE_LL = 14; public const int WH_MOUSE_LL = 14;
public const int WM_CHANGECBCHAIN = 0x030D; public const int WM_CHANGECBCHAIN = 0x030D;
public const int WM_DRAWCLIPBOARD = 0x308; public const int WM_DRAWCLIPBOARD = 0x308;
public const int WM_KEYDOWN = 0x0100;
public const int WM_KEYUP = 0x0101;
public const int WM_LBUTTONDOWN = 0x0201; public const int WM_LBUTTONDOWN = 0x0201;
public const int WM_MOUSEMOVE = 0x0200; public const int WM_MOUSEMOVE = 0x0200;
private const string _GDI32_DLL = "gdi32.dll"; private const string _GDI32_DLL = "gdi32.dll";
@ -49,6 +57,10 @@ internal static partial class Win32
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial int ReleaseDC(nint hWnd, nint dc); internal static partial int ReleaseDC(nint hWnd, nint dc);
[LibraryImport(_USER32_DLL)]
internal static partial uint SendInput(uint cInputs, [MarshalAs(UnmanagedType.LPArray)] InputStruct[] inputs
, int cbSize);
[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);
@ -72,10 +84,37 @@ internal static partial class Win32
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool UnhookWindowsHookExA(nint hhk); internal static partial bool UnhookWindowsHookExA(nint hhk);
[StructLayout(LayoutKind.Explicit)]
public struct InputStruct
{
[FieldOffset(8)] public KeybdInputStruct ki;
[FieldOffset(0)] public uint type;
}
[StructLayout(LayoutKind.Explicit)]
public struct KbdllhooksStruct
{
[FieldOffset(16)] public nint dwExtraInfo;
[FieldOffset(8)] public uint flags;
[FieldOffset(4)] public uint scanCode;
[FieldOffset(12)] public uint time;
[FieldOffset(0)] public uint vkCode;
}
[StructLayout(LayoutKind.Explicit)]
public struct KeybdInputStruct
{
[FieldOffset(20)] public long _; // 补位以匹配 UNION的MOUSEINPUT参数 28bytes
[FieldOffset(12)] public nint dwExtraInfo;
[FieldOffset(4)] public uint dwFlags;
[FieldOffset(8)] public uint time;
[FieldOffset(2)] public ushort wScan;
[FieldOffset(0)] public ushort wVk;
}
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
internal ref struct Systemtime internal ref struct Systemtime
{ {
#pragma warning disable SA1307
[FieldOffset(6)] public ushort wDay; [FieldOffset(6)] public ushort wDay;
[FieldOffset(4)] public ushort wDayOfWeek; [FieldOffset(4)] public ushort wDayOfWeek;
[FieldOffset(8)] public ushort wHour; [FieldOffset(8)] public ushort wHour;
@ -84,6 +123,5 @@ internal static partial class Win32
[FieldOffset(2)] public ushort wMonth; [FieldOffset(2)] public ushort wMonth;
[FieldOffset(12)] public ushort wSecond; [FieldOffset(12)] public ushort wSecond;
[FieldOffset(0)] public ushort wYear; [FieldOffset(0)] public ushort wYear;
#pragma warning restore SA1307
} }
} }

View File

@ -9,9 +9,13 @@ internal static class BaiduSignCracker
public static string Sign(string text) public static string Sign(string text)
{ {
var e = new List<int>(text.Length); var hash = text.Length > 30
for (var i = 0; i < text.Length; i++) { ? string.Concat(text.AsSpan()[..10], text.AsSpan(text.Length / 2 - 5, 10), text.AsSpan()[^10..])
var k = (int)text[i]; : text;
var e = new List<int>(hash.Length);
for (var i = 0; i < hash.Length; i++) {
var k = (int)hash[i];
switch (k) { switch (k) {
case < 128: case < 128:
e.Add(k); e.Add(k);
@ -20,8 +24,8 @@ internal static class BaiduSignCracker
e.Add((k >> 6) | 192); e.Add((k >> 6) | 192);
break; break;
default: { default: {
if ((k & 64512) == 55296 && i + 1 < text.Length && (text[i + 1] & 64512) == 56320) { if ((k & 64512) == 55296 && i + 1 < hash.Length && (hash[i + 1] & 64512) == 56320) {
k = 65536 + ((k & 1023) << 10) + (text[++i] & 1023); k = 65536 + ((k & 1023) << 10) + (hash[++i] & 1023);
e.Add((k >> 18) | 240); e.Add((k >> 18) | 240);
e.Add(((k >> 12) & 63) | 128); e.Add(((k >> 12) & 63) | 128);
} }

View File

@ -1,5 +1,7 @@
#if NET7_0_WINDOWS #if NET7_0_WINDOWS
using System.Net; using System.Net;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Dot.Native; using Dot.Native;
using Dot.Tran.Dto; using Dot.Tran.Dto;
@ -9,23 +11,22 @@ using Size = System.Drawing.Size;
namespace Dot.Tran; namespace Dot.Tran;
[SupportedOSPlatform(nameof(OSPlatform.Windows))]
internal sealed partial class FrmMain : Form internal sealed partial class FrmMain : Form
{ {
private const int _HIDING_MIL_SECS = 5000; // 隐藏窗体时间(秒 private const int _RETRY_WAIT_MIL_SEC = 1000; // 重试等待时间(秒)
private const int _RETRY_WAIT_MIL_SEC = 1000; // 重试等待时间(秒) private const string _TRANSLATE_API_URL = $"{_TRANSLATE_HOME_URL}/v2transapi";
private const string _TRANSLATE_API_URL = "https://fanyi.baidu.com/v2transapi"; private const string _TRANSLATE_HOME_URL = "https://fanyi.baidu.com";
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 MouseHook _mouseHook = new(); private readonly HttpClient _httpClient = new();
private readonly Size _mouseMargin = new(10, 10); private readonly KeyboardHook _keyboardHook = new();
private bool _disposed; private readonly Label _labelDest = new(); // 显示翻译内容的文本框
private DateTime? _latestActiveTime; // 窗体最后激活时间 private readonly MouseHook _mouseHook = new();
private nint _nextHwnd; // 下一个剪贴板监视链对象句柄 private readonly Size _mouseMargin = new(10, 10);
private string _token = "ae72ebad4113270fd26ada5125301268"; private bool _capsLockPressed; // 大写键按下进行翻译区分ctrl+c
private bool _disposed;
private nint _nextClipViewer; // 下一个剪贴板监视链对象句柄
private string _token = "ae72ebad4113270fd26ada5125301268";
public FrmMain() public FrmMain()
{ {
@ -34,9 +35,7 @@ internal sealed partial class FrmMain : Form
InitLabelDest(); InitLabelDest();
InitHttpClient(); InitHttpClient();
_nextHwnd = Win32.SetClipboardViewer(Handle); _nextClipViewer = Win32.SetClipboardViewer(Handle);
Task.Run(HideWindow);
} }
~FrmMain() ~FrmMain()
@ -53,14 +52,13 @@ internal sealed partial class FrmMain : Form
} }
if (disposing) { if (disposing) {
_mre = null; // 结束定时隐藏窗体线程
_mre?.Dispose();
_httpClient?.Dispose(); _httpClient?.Dispose();
_labelDest?.Dispose(); _labelDest?.Dispose();
_mouseHook?.Dispose(); _mouseHook?.Dispose();
_keyboardHook?.Dispose();
} }
Win32.ChangeClipboardChain(Handle, _nextHwnd); // 从剪贴板监视链移除本窗体 Win32.ChangeClipboardChain(Handle, _nextClipViewer); // 从剪贴板监视链移除本窗体
_disposed = true; _disposed = true;
} }
@ -68,18 +66,21 @@ internal sealed partial class FrmMain : Form
{ {
void SendToNext(Message message) void SendToNext(Message message)
{ {
_ = Win32.SendMessageA(_nextHwnd, (uint)message.Msg, message.WParam, message.LParam); _ = Win32.SendMessageA(_nextClipViewer, (uint)message.Msg, message.WParam, message.LParam);
} }
switch (m.Msg) { switch (m.Msg) {
case Win32.WM_DRAWCLIPBOARD: case Win32.WM_DRAWCLIPBOARD:
DisplayClipboardData(); if (_capsLockPressed) {
_capsLockPressed = false;
DisplayClipboardData();
}
SendToNext(m); SendToNext(m);
break; break;
case Win32.WM_CHANGECBCHAIN: case Win32.WM_CHANGECBCHAIN:
Console.WriteLine(Win32.WM_CHANGECBCHAIN); if (m.WParam == _nextClipViewer) {
if (m.WParam == _nextHwnd) { _nextClipViewer = m.LParam;
_nextHwnd = m.LParam;
} }
else { else {
SendToNext(m); SendToNext(m);
@ -93,7 +94,7 @@ internal sealed partial class FrmMain : Form
} }
[GeneratedRegex("token: '(\\w+)'")] [GeneratedRegex("token: '(\\w+)'")]
private static partial Regex MyRegex(); private static partial Regex TokenRegex();
/// <summary> /// <summary>
/// 显示剪贴板内容. /// 显示剪贴板内容.
@ -107,7 +108,8 @@ internal sealed partial class FrmMain : Form
_labelDest.Text = Str.Translating; _labelDest.Text = Str.Translating;
Task.Run(() => { Task.Run(() => {
var translateText = _labelDest.Text = TranslateText(clipText); var translateText = TranslateText(clipText);
ClipboardService.SetText(translateText);
Invoke(() => { _labelDest.Text = translateText; }); Invoke(() => { _labelDest.Text = translateText; });
}); });
@ -115,55 +117,70 @@ internal sealed partial class FrmMain : Form
point.Offset(new Point(_mouseMargin)); point.Offset(new Point(_mouseMargin));
Location = point; Location = point;
Show(); Show();
_latestActiveTime = DateTime.Now;
_mre.Set();
}
private async Task HideWindow()
{
while (_mre is not null) {
while (Visible) {
await Task.Delay(100);
if (_latestActiveTime is null ||
!((DateTime.Now - _latestActiveTime.Value).TotalMilliseconds > _HIDING_MIL_SECS)) {
continue;
}
Invoke(Hide);
}
_mre.WaitOne();
}
} }
private void InitForm() private void InitForm()
{ {
AutoSize = true; AutoSize = true;
AutoSizeMode = AutoSizeMode.GrowAndShrink; AutoSizeMode = AutoSizeMode.GrowAndShrink;
MaximumSize = Screen.FromHandle(Handle).Bounds.Size / 2;
FormBorderStyle = FormBorderStyle.None; FormBorderStyle = FormBorderStyle.None;
Opacity = _WINDOW_OPACITY;
TopMost = true; TopMost = true;
Visible = false; Visible = false;
} }
private void InitHook() private unsafe void InitHook()
{ {
_mouseHook.MouseMoveEvent += (_, e) => { _mouseHook.MouseMoveEvent += (_, e) => {
var point = new Point(e.X, e.Y); var point = new Point(e.X, e.Y);
point.Offset(new Point(_mouseMargin)); point.Offset(new Point(_mouseMargin));
Location = point; Location = point;
}; };
_keyboardHook.KeyUpEvent += (_, e) => {
switch (e.vkCode) {
case VkCode.VK_CAPITAL: {
var keyInputs = new Win32.InputStruct[4];
keyInputs[0].type = Win32.INPUT_KEYBOARD;
keyInputs[0].ki.wVk = VkCode.VK_CONTROL;
keyInputs[1].type = Win32.INPUT_KEYBOARD;
keyInputs[1].ki.wVk = VkCode.VK_C;
keyInputs[2].type = Win32.INPUT_KEYBOARD;
keyInputs[2].ki.wVk = VkCode.VK_C;
keyInputs[2].ki.dwFlags = Win32.KEYEVENTF_KEYUP;
keyInputs[3].type = Win32.INPUT_KEYBOARD;
keyInputs[3].ki.wVk = VkCode.VK_CONTROL;
keyInputs[3].ki.dwFlags = Win32.KEYEVENTF_KEYUP;
Win32.SendInput((uint)keyInputs.Length, keyInputs, sizeof(Win32.InputStruct));
_capsLockPressed = true;
return true;
}
case VkCode.VK_ESCAPE:
Hide();
break;
default:
return false;
}
return false;
};
} }
private void InitHttpClient() private void InitHttpClient()
{ {
_httpClient.DefaultRequestHeaders.Add( // _httpClient.DefaultRequestHeaders.Add( //
"User-Agent" "User-Agent"
, " Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36"); , "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36");
} }
private void InitLabelDest() private void InitLabelDest()
{ {
_labelDest.Font = new Font(_labelDest.Font.FontFamily, 16);
_labelDest.BorderStyle = BorderStyle.None; _labelDest.BorderStyle = BorderStyle.None;
_labelDest.Dock = DockStyle.Fill; _labelDest.Dock = DockStyle.Fill;
_labelDest.AutoSize = true; _labelDest.AutoSize = true;
@ -173,11 +190,7 @@ internal sealed partial class FrmMain : Form
private string TranslateText(string sourceText) private string TranslateText(string sourceText)
{ {
while (true) { while (true) {
var hash = sourceText.Length > 30 var sign = BaiduSignCracker.Sign(sourceText);
? string.Concat(sourceText.AsSpan()[..10], sourceText.AsSpan(sourceText.Length / 2 - 5, 10)
, sourceText.AsSpan()[^10..])
: sourceText;
var sign = BaiduSignCracker.Sign(hash);
var content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>> { var content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>> {
new("from", "auto") new("from", "auto")
, new("to", "zh") , new("to", "zh")
@ -204,7 +217,7 @@ internal sealed partial class FrmMain : Form
_httpClient.DefaultRequestHeaders.Remove(nameof(Cookie)); _httpClient.DefaultRequestHeaders.Remove(nameof(Cookie));
_httpClient.DefaultRequestHeaders.Add(nameof(Cookie), cookie); _httpClient.DefaultRequestHeaders.Add(nameof(Cookie), cookie);
var html = _httpClient.GetStringAsync(_TRANSLATE_HOME_URL).Result; var html = _httpClient.GetStringAsync(_TRANSLATE_HOME_URL).Result;
_token = MyRegex().Match(html).Groups[1].Value; _token = TokenRegex().Match(html).Groups[1].Value;
} }
} }
} }

View File

@ -4,14 +4,18 @@ using System.Runtime.Versioning;
namespace Dot.Tran; namespace Dot.Tran;
[Description(nameof(Str.TranslateTool))]
[Localization(typeof(Str))]
internal sealed class Main : ToolBase<Option> internal sealed class Main : ToolBase<Option>
{ {
[SupportedOSPlatform(nameof(OSPlatform.Windows))] [SupportedOSPlatform(nameof(OSPlatform.Windows))]
protected override Task Core() protected override Task Core()
{ {
AnsiConsole.MarkupLine(Str.StartTranslate);
AnsiConsole.MarkupLine(Str.HideTranslate);
var th = new Thread(() => { var th = new Thread(() => {
using var frm = new FrmMain(); using var frm = new FrmMain();
Application.Run(frm); Application.Run();
}); });
th.SetApartmentState(ApartmentState.STA); th.SetApartmentState(ApartmentState.STA);
th.Start(); th.Start();