diff --git a/src/AssemblyInfo.cs b/src/AssemblyInfo.cs
index 21578b5..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.6";
+ 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..ff98490 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..97459db
--- /dev/null
+++ b/src/Native/KeyboardHook.cs
@@ -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
\ 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..181ef2e 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,8 @@ internal sealed partial class FrmMain : Form
_labelDest.Text = Str.Translating;
Task.Run(() => {
- var translateText = _labelDest.Text = TranslateText(clipText);
+ var translateText = TranslateText(clipText);
+ ClipboardService.SetText(translateText);
Invoke(() => { _labelDest.Text = translateText; });
});
@@ -115,55 +117,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 +190,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 +217,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