From 8fa47065afd2562b35a5febb4a4e311932ecee4a Mon Sep 17 00:00:00 2001 From: nsnail Date: Tue, 20 Dec 2022 16:35:31 +0800 Subject: [PATCH 1/3] =?UTF-8?q?<=20=20=20ver>=20+=201.1.7.1=20=20*?= =?UTF-8?q?=20=E7=BF=BB=E8=AF=91=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/AssemblyInfo.cs | 2 +- src/Lang/Str.en-US.resx | 17 +++- src/Lang/Str.resx | 9 ++ src/Native/KeyboardHook.cs | 69 ++++++++++++++ src/Native/VkCode.cs | 172 +++++++++++++++++++++++++++++++++++ src/Native/Win32.cs | 42 ++++++++- src/Tran/BaiduSignCracker.cs | 14 ++- src/Tran/FrmMain.cs | 122 ++++++++++++++----------- src/Tran/Main.cs | 6 +- 9 files changed, 386 insertions(+), 67 deletions(-) create mode 100644 src/Native/KeyboardHook.cs create mode 100644 src/Native/VkCode.cs diff --git a/src/AssemblyInfo.cs b/src/AssemblyInfo.cs index 7b70604..ed3e225 100644 --- a/src/AssemblyInfo.cs +++ b/src/AssemblyInfo.cs @@ -24,5 +24,5 @@ internal static class AssemblyInfo public const string ASSEMBLY_PRODUCT = "dot"; public const string ASSEMBLY_TITLE = "功能全面的实用工具 - 程序员的瑞士军刀"; public const string ASSEMBLY_VERSION = _VERSION; - private const string _VERSION = "1.1.7"; + private const string _VERSION = "1.1.7.1"; } \ No newline at end of file diff --git a/src/Lang/Str.en-US.resx b/src/Lang/Str.en-US.resx index 2d383da..726d0a4 100644 --- a/src/Lang/Str.en-US.resx +++ b/src/Lang/Str.en-US.resx @@ -1,7 +1,6 @@ - + - + @@ -254,4 +253,16 @@ Buffer size (kilobytes) + + In translation... + + + Press [green] Esc[/] to hide the translation + + + Select the text and press [green] Capslock[/] to start the translation + + + Translation tools + \ No newline at end of file diff --git a/src/Lang/Str.resx b/src/Lang/Str.resx index 9562803..317ab0a 100644 --- a/src/Lang/Str.resx +++ b/src/Lang/Str.resx @@ -267,4 +267,13 @@ 翻译中... + + 按下 [green]Esc[/] 隐藏译文 + + + 选中文本按下 [green]Capslock[/] 开始翻译 + + + 翻译工具 + \ No newline at end of file diff --git a/src/Native/KeyboardHook.cs b/src/Native/KeyboardHook.cs new file mode 100644 index 0000000..5338080 --- /dev/null +++ b/src/Native/KeyboardHook.cs @@ -0,0 +1,69 @@ +// 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) { + return Win32.CallNextHookEx(_hookId, nCode, wParam, lParam); + } + + var hookStruct = (Win32.KbdllhooksStruct)Marshal.PtrToStructure(lParam, typeof(Win32.KbdllhooksStruct))!; + return KeyUpEvent?.Invoke(null, hookStruct) ?? false ? -1 : nint.Zero; + } +} + +#endif \ No newline at end of file diff --git a/src/Native/VkCode.cs b/src/Native/VkCode.cs new file mode 100644 index 0000000..a00173a --- /dev/null +++ b/src/Native/VkCode.cs @@ -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; // 缩放键 +} \ No newline at end of file diff --git a/src/Native/Win32.cs b/src/Native/Win32.cs index 3f91e6c..4d62865 100644 --- a/src/Native/Win32.cs +++ b/src/Native/Win32.cs @@ -1,6 +1,8 @@ // ReSharper disable UnusedMember.Global // ReSharper disable UnusedMethodReturnValue.Global +#pragma warning disable SA1307 + using System.Runtime.InteropServices; namespace Dot.Native; @@ -9,10 +11,16 @@ internal static partial class Win32 { public const int CS_DROP_SHADOW = 0x20000; 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 WH_KEYBOARD_LL = 13; public const int WH_MOUSE_LL = 14; public const int WM_CHANGECBCHAIN = 0x030D; 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_MOUSEMOVE = 0x0200; private const string _GDI32_DLL = "gdi32.dll"; @@ -49,6 +57,10 @@ internal static partial class Win32 [LibraryImport(_USER32_DLL)] 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)] 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)] 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)] internal ref struct Systemtime { - #pragma warning disable SA1307 [FieldOffset(6)] public ushort wDay; [FieldOffset(4)] public ushort wDayOfWeek; [FieldOffset(8)] public ushort wHour; @@ -84,6 +123,5 @@ internal static partial class Win32 [FieldOffset(2)] public ushort wMonth; [FieldOffset(12)] public ushort wSecond; [FieldOffset(0)] public ushort wYear; - #pragma warning restore SA1307 } } \ No newline at end of file diff --git a/src/Tran/BaiduSignCracker.cs b/src/Tran/BaiduSignCracker.cs index 6f90da0..7146ab0 100644 --- a/src/Tran/BaiduSignCracker.cs +++ b/src/Tran/BaiduSignCracker.cs @@ -9,9 +9,13 @@ internal static class BaiduSignCracker public static string Sign(string text) { - var e = new List(text.Length); - for (var i = 0; i < text.Length; i++) { - var k = (int)text[i]; + var hash = text.Length > 30 + ? string.Concat(text.AsSpan()[..10], text.AsSpan(text.Length / 2 - 5, 10), text.AsSpan()[^10..]) + : text; + + var e = new List(hash.Length); + for (var i = 0; i < hash.Length; i++) { + var k = (int)hash[i]; switch (k) { case < 128: e.Add(k); @@ -20,8 +24,8 @@ internal static class BaiduSignCracker 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); + if ((k & 64512) == 55296 && i + 1 < hash.Length && (hash[i + 1] & 64512) == 56320) { + k = 65536 + ((k & 1023) << 10) + (hash[++i] & 1023); e.Add((k >> 18) | 240); e.Add(((k >> 12) & 63) | 128); } diff --git a/src/Tran/FrmMain.cs b/src/Tran/FrmMain.cs index f8b9365..385058e 100644 --- a/src/Tran/FrmMain.cs +++ b/src/Tran/FrmMain.cs @@ -1,5 +1,7 @@ #if NET7_0_WINDOWS using System.Net; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Text.RegularExpressions; using Dot.Native; using Dot.Tran.Dto; @@ -9,23 +11,22 @@ using Size = System.Drawing.Size; namespace Dot.Tran; +[SupportedOSPlatform(nameof(OSPlatform.Windows))] internal sealed partial class FrmMain : Form { - private const int _HIDING_MIL_SECS = 5000; // 隐藏窗体时间(秒 - private const int _RETRY_WAIT_MIL_SEC = 1000; // 重试等待时间(秒) - private const string _TRANSLATE_API_URL = "https://fanyi.baidu.com/v2transapi"; - 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 const int _RETRY_WAIT_MIL_SEC = 1000; // 重试等待时间(秒) + private const string _TRANSLATE_API_URL = $"{_TRANSLATE_HOME_URL}/v2transapi"; + private const string _TRANSLATE_HOME_URL = "https://fanyi.baidu.com"; - private readonly MouseHook _mouseHook = new(); - private readonly Size _mouseMargin = new(10, 10); - private bool _disposed; - private DateTime? _latestActiveTime; // 窗体最后激活时间 - private nint _nextHwnd; // 下一个剪贴板监视链对象句柄 - private string _token = "ae72ebad4113270fd26ada5125301268"; + private readonly HttpClient _httpClient = new(); + private readonly KeyboardHook _keyboardHook = new(); + private readonly Label _labelDest = new(); // 显示翻译内容的文本框 + private readonly MouseHook _mouseHook = new(); + private readonly Size _mouseMargin = new(10, 10); + private bool _capsLockPressed; // 大写键按下进行翻译,区分ctrl+c + private bool _disposed; + private nint _nextClipViewer; // 下一个剪贴板监视链对象句柄 + private string _token = "ae72ebad4113270fd26ada5125301268"; public FrmMain() { @@ -34,9 +35,7 @@ internal sealed partial class FrmMain : Form InitLabelDest(); InitHttpClient(); - _nextHwnd = Win32.SetClipboardViewer(Handle); - - Task.Run(HideWindow); + _nextClipViewer = Win32.SetClipboardViewer(Handle); } ~FrmMain() @@ -53,14 +52,13 @@ internal sealed partial class FrmMain : Form } if (disposing) { - _mre = null; // 结束定时隐藏窗体线程 - _mre?.Dispose(); _httpClient?.Dispose(); _labelDest?.Dispose(); _mouseHook?.Dispose(); + _keyboardHook?.Dispose(); } - Win32.ChangeClipboardChain(Handle, _nextHwnd); // 从剪贴板监视链移除本窗体 + Win32.ChangeClipboardChain(Handle, _nextClipViewer); // 从剪贴板监视链移除本窗体 _disposed = true; } @@ -68,18 +66,21 @@ internal sealed partial class FrmMain : Form { 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) { case Win32.WM_DRAWCLIPBOARD: - DisplayClipboardData(); + if (_capsLockPressed) { + _capsLockPressed = false; + DisplayClipboardData(); + } + SendToNext(m); break; case Win32.WM_CHANGECBCHAIN: - Console.WriteLine(Win32.WM_CHANGECBCHAIN); - if (m.WParam == _nextHwnd) { - _nextHwnd = m.LParam; + if (m.WParam == _nextClipViewer) { + _nextClipViewer = m.LParam; } else { SendToNext(m); @@ -93,7 +94,7 @@ internal sealed partial class FrmMain : Form } [GeneratedRegex("token: '(\\w+)'")] - private static partial Regex MyRegex(); + private static partial Regex TokenRegex(); /// /// 显示剪贴板内容. @@ -107,7 +108,7 @@ internal sealed partial class FrmMain : Form _labelDest.Text = Str.Translating; Task.Run(() => { - var translateText = _labelDest.Text = TranslateText(clipText); + var translateText = TranslateText(clipText); Invoke(() => { _labelDest.Text = translateText; }); }); @@ -115,55 +116,70 @@ internal sealed partial class FrmMain : Form point.Offset(new Point(_mouseMargin)); Location = point; 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() { AutoSize = true; AutoSizeMode = AutoSizeMode.GrowAndShrink; + MaximumSize = Screen.FromHandle(Handle).Bounds.Size / 2; FormBorderStyle = FormBorderStyle.None; - Opacity = _WINDOW_OPACITY; TopMost = true; Visible = false; } - private void InitHook() + private unsafe void InitHook() { _mouseHook.MouseMoveEvent += (_, e) => { var point = new Point(e.X, e.Y); point.Offset(new Point(_mouseMargin)); 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() { _httpClient.DefaultRequestHeaders.Add( // "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() { + _labelDest.Font = new Font(_labelDest.Font.FontFamily, 16); _labelDest.BorderStyle = BorderStyle.None; _labelDest.Dock = DockStyle.Fill; _labelDest.AutoSize = true; @@ -173,11 +189,7 @@ internal sealed partial class FrmMain : Form private string TranslateText(string sourceText) { while (true) { - var hash = sourceText.Length > 30 - ? string.Concat(sourceText.AsSpan()[..10], sourceText.AsSpan(sourceText.Length / 2 - 5, 10) - , sourceText.AsSpan()[^10..]) - : sourceText; - var sign = BaiduSignCracker.Sign(hash); + var sign = BaiduSignCracker.Sign(sourceText); var content = new FormUrlEncodedContent(new List> { new("from", "auto") , new("to", "zh") @@ -204,7 +216,7 @@ internal sealed partial class FrmMain : Form _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; + _token = TokenRegex().Match(html).Groups[1].Value; } } } diff --git a/src/Tran/Main.cs b/src/Tran/Main.cs index a00f763..e5c6569 100644 --- a/src/Tran/Main.cs +++ b/src/Tran/Main.cs @@ -4,14 +4,18 @@ using System.Runtime.Versioning; namespace Dot.Tran; +[Description(nameof(Str.TranslateTool))] +[Localization(typeof(Str))] internal sealed class Main : ToolBase