This commit is contained in:
nsnail 2022-12-21 10:47:26 +08:00
parent a744d70eba
commit 92e8986500
9 changed files with 90 additions and 76 deletions

View File

@ -7,6 +7,8 @@ namespace Dot.Color;
[Description(nameof(Str.ScreenPixelTool))] [Description(nameof(Str.ScreenPixelTool))]
[Localization(typeof(Str))] [Localization(typeof(Str))]
[SupportedOSPlatform(nameof(OSPlatform.Windows))] [SupportedOSPlatform(nameof(OSPlatform.Windows))]
// ReSharper disable once ClassNeverInstantiated.Global
internal sealed class Main : ToolBase<Option> internal sealed class Main : ToolBase<Option>
{ {
protected override Task Core() protected override Task Core()

View File

@ -57,6 +57,7 @@ internal sealed class KeyboardHook : IDisposable
private nint HookCallback(int nCode, nint wParam, nint lParam) private nint HookCallback(int nCode, nint wParam, nint lParam)
{ {
// ReSharper disable once InvertIf
if (nCode >= 0 && wParam == Win32.WM_KEYDOWN) { if (nCode >= 0 && wParam == Win32.WM_KEYDOWN) {
var hookStruct = (Win32.KbdllhooksStruct)Marshal.PtrToStructure(lParam, typeof(Win32.KbdllhooksStruct))!; var hookStruct = (Win32.KbdllhooksStruct)Marshal.PtrToStructure(lParam, typeof(Win32.KbdllhooksStruct))!;
if (KeyUpEvent?.Invoke(null, hookStruct) ?? false) { if (KeyUpEvent?.Invoke(null, hookStruct) ?? false) {

View File

@ -55,6 +55,7 @@ internal sealed class MouseHook : IDisposable
private nint HookCallback(int nCode, nint wParam, nint lParam) private nint HookCallback(int nCode, nint wParam, nint lParam)
{ {
// ReSharper disable once InvertIf
if (wParam == Win32.WM_MOUSEMOVE) { if (wParam == Win32.WM_MOUSEMOVE) {
var hookStruct = (Msllhookstruct)Marshal.PtrToStructure(lParam, typeof(Msllhookstruct))!; var hookStruct = (Msllhookstruct)Marshal.PtrToStructure(lParam, typeof(Msllhookstruct))!;
MouseMoveEvent?.Invoke(null, new MouseEventArgs(MouseButtons.None, 0, hookStruct.X, hookStruct.Y, 0)); MouseMoveEvent?.Invoke(null, new MouseEventArgs(MouseButtons.None, 0, hookStruct.X, hookStruct.Y, 0));

View File

@ -1,8 +1,10 @@
// ReSharper disable UnusedMember.Global
#pragma warning disable CS1591 #pragma warning disable CS1591
namespace Dot.Native; namespace Dot.Native;
public class VkCode internal static class VkCode
{ {
public const int VK_A = 0x41; // A 键 public const int VK_A = 0x41; // A 键
public const int VK_ACCEPT = 0x1E; // IME 接受 public const int VK_ACCEPT = 0x1E; // IME 接受

View File

@ -1,7 +1,7 @@
// ReSharper disable UnusedMember.Global // ReSharper disable UnusedMember.Global
// ReSharper disable UnusedMethodReturnValue.Global // ReSharper disable UnusedMethodReturnValue.Global
#pragma warning disable SA1307 #pragma warning disable SA1307, SX1309
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -30,59 +30,69 @@ internal static partial class Win32
public delegate nint HookProc(int nCode, nint wParam, nint lParam); public delegate nint HookProc(int nCode, nint wParam, nint lParam);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial nint CallNextHookEx(nint hhk, int nCode, nint wParam, nint lParam); public static partial nint CallNextHookEx(nint hhk, int nCode, nint wParam, nint lParam);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool ChangeClipboardChain(nint hWndRemove, nint hWndNewNext); public static partial bool ChangeClipboardChain(nint hWndRemove, nint hWndNewNext);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial int GetClassLongA(nint hWnd, int nIndex); public static partial int GetClassLongA(nint hWnd, int nIndex);
[LibraryImport(_KERNEL32_DLL)] [LibraryImport(_KERNEL32_DLL)]
internal static partial nint GetConsoleWindow(); public static partial nint GetConsoleWindow();
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial nint GetDesktopWindow(); public static partial nint GetDesktopWindow();
[LibraryImport(_KERNEL32_DLL, StringMarshalling = StringMarshalling.Utf16)] [LibraryImport(_KERNEL32_DLL, StringMarshalling = StringMarshalling.Utf16)]
internal static partial nint GetModuleHandleA(string lpModuleName); public static partial nint GetModuleHandleA(string lpModuleName);
[LibraryImport(_GDI32_DLL)] [LibraryImport(_GDI32_DLL)]
internal static partial uint GetPixel(nint dc, int x, int y); public static partial uint GetPixel(nint dc, int x, int y);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial nint GetWindowDC(nint hWnd); public static partial nint GetWindowDC(nint hWnd);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial int ReleaseDC(nint hWnd, nint dc); public static partial int ReleaseDC(nint hWnd, nint dc);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial uint SendInput(uint cInputs, [MarshalAs(UnmanagedType.LPArray)] InputStruct[] inputs public static partial uint SendInput(uint cInputs, [MarshalAs(UnmanagedType.LPArray)] InputStruct[] inputs
, int cbSize); , int cbSize);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial int SendMessageA(nint hwnd, uint wMsg, nint wParam, nint lParam); public static partial int SendMessageA(nint hwnd, uint wMsg, nint wParam, nint lParam);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial int SetClassLongA(nint hWnd, int nIndex, int dwNewLong); public static partial int SetClassLongA(nint hWnd, int nIndex, int dwNewLong);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial int SetClipboardViewer(nint hWnd); public static partial int SetClipboardViewer(nint hWnd);
[LibraryImport(_KERNEL32_DLL)] [LibraryImport(_KERNEL32_DLL)]
internal static partial void SetLocalTime(Systemtime st); public static partial void SetLocalTime(Systemtime st);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
internal static partial nint SetWindowsHookExA(int idHook, HookProc lpfn, nint hMod, uint dwThreadId); public static partial nint SetWindowsHookExA(int idHook, HookProc lpfn, nint hMod, uint dwThreadId);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool ShowWindow(nint hWnd, int nCmdShow); public static partial bool ShowWindow(nint hWnd, int nCmdShow);
[LibraryImport(_USER32_DLL)] [LibraryImport(_USER32_DLL)]
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool UnhookWindowsHookExA(nint hhk); public static partial bool UnhookWindowsHookExA(nint hhk);
[StructLayout(LayoutKind.Explicit)]
public readonly struct KbdllhooksStruct
{
[FieldOffset(0)] public readonly uint vkCode;
[FieldOffset(16)] private readonly nint dwExtraInfo;
[FieldOffset(8)] private readonly uint flags;
[FieldOffset(4)] private readonly uint scanCode;
[FieldOffset(12)] private readonly uint time;
}
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct InputStruct public struct InputStruct
@ -91,29 +101,19 @@ internal static partial class Win32
[FieldOffset(0)] public uint type; [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)] [StructLayout(LayoutKind.Explicit)]
public struct KeybdInputStruct public struct KeybdInputStruct
{ {
[FieldOffset(20)] public long _; // 补位以匹配 UNION的MOUSEINPUT参数 28bytes [FieldOffset(4)] public uint dwFlags;
[FieldOffset(12)] public nint dwExtraInfo; [FieldOffset(0)] public ushort wVk;
[FieldOffset(4)] public uint dwFlags; [FieldOffset(20)] private readonly long _; // 补位以匹配 UNION的MOUSEINPUT参数 28bytes
[FieldOffset(8)] public uint time; [FieldOffset(12)] private readonly nint dwExtraInfo;
[FieldOffset(2)] public ushort wScan; [FieldOffset(8)] private readonly uint time;
[FieldOffset(0)] public ushort wVk; [FieldOffset(2)] private readonly ushort wScan;
} }
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
internal ref struct Systemtime public ref struct Systemtime
{ {
[FieldOffset(6)] public ushort wDay; [FieldOffset(6)] public ushort wDay;
[FieldOffset(4)] public ushort wDayOfWeek; [FieldOffset(4)] public ushort wDayOfWeek;

View File

@ -1,5 +1,7 @@
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
// ReSharper disable ClassNeverInstantiated.Global // ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable UnusedMember.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
#pragma warning disable IDE1006,SA1300 #pragma warning disable IDE1006,SA1300
namespace Dot.Tran.Dto; namespace Dot.Tran.Dto;
@ -47,6 +49,7 @@ internal sealed record BaiduTranslateResultDto
public sealed record Trans_result public sealed record Trans_result
{ {
// ReSharper disable once CollectionNeverUpdated.Global
public List<DataItem> data { get; set; } public List<DataItem> data { get; set; }
public string from { get; set; } public string from { get; set; }

View File

@ -7,6 +7,8 @@ namespace Dot.Tran;
[Description(nameof(Str.TranslateTool))] [Description(nameof(Str.TranslateTool))]
[Localization(typeof(Str))] [Localization(typeof(Str))]
// ReSharper disable once ClassNeverInstantiated.Global
internal sealed class Main : ToolBase<Option> internal sealed class Main : ToolBase<Option>
{ {
[SupportedOSPlatform(nameof(OSPlatform.Windows))] [SupportedOSPlatform(nameof(OSPlatform.Windows))]

View File

@ -1,3 +1,4 @@
namespace Dot.Tran; namespace Dot.Tran;
// ReSharper disable once ClassNeverInstantiated.Global
internal sealed class Option : OptionBase { } internal sealed class Option : OptionBase { }

View File

@ -14,19 +14,18 @@ namespace Dot.Tran;
[SupportedOSPlatform(nameof(OSPlatform.Windows))] [SupportedOSPlatform(nameof(OSPlatform.Windows))]
internal sealed partial class WinMain : Form internal sealed partial class WinMain : Form
{ {
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 = $"{_TRANSLATE_HOME_URL}/v2transapi";
private const string _TRANSLATE_HOME_URL = "https://fanyi.baidu.com"; private const string _TRANSLATE_HOME_URL = "https://fanyi.baidu.com";
private readonly HttpClient _httpClient = new();
private readonly HttpClient _httpClient = new();
private readonly KeyboardHook _keyboardHook = new(); private readonly KeyboardHook _keyboardHook = new();
private readonly Label _labelDest = new(); // 显示翻译内容的文本框 private readonly Label _labelDest = new();
private readonly MouseHook _mouseHook = new(); private readonly MouseHook _mouseHook = new();
private readonly Size _mouseMargin = new(10, 10); private readonly Size _mouseMargin = new(10, 10); // 窗体与鼠标指针的距离
private bool _capsLockPressed; // 大写键按下进行翻译区分ctrl+c private bool _capsLockPressed; // 大写键按下进行翻译区分ctrl+c
private bool _disposed; private bool _disposed;
private nint _nextClipViewer; // 下一个剪贴板监视链对象句柄 private nint _nextClipMonitor; // 下一个剪贴板监视链对象句柄
private string _token = "ae72ebad4113270fd26ada5125301268"; private string _token = "ae72ebad4113270fd26ada5125301268"; // 翻译api token
public WinMain() public WinMain()
{ {
@ -34,8 +33,7 @@ internal sealed partial class WinMain : Form
InitHook(); InitHook();
InitLabelDest(); InitLabelDest();
InitHttpClient(); InitHttpClient();
InitClipMonitor();
_nextClipViewer = Win32.SetClipboardViewer(Handle);
} }
~WinMain() ~WinMain()
@ -58,7 +56,7 @@ internal sealed partial class WinMain : Form
_keyboardHook?.Dispose(); _keyboardHook?.Dispose();
} }
Win32.ChangeClipboardChain(Handle, _nextClipViewer); // 从剪贴板监视链移除本窗体 Win32.ChangeClipboardChain(Handle, _nextClipMonitor); // 从剪贴板监视链移除本窗体
_disposed = true; _disposed = true;
} }
@ -66,21 +64,21 @@ internal sealed partial class WinMain : Form
{ {
void SendToNext(Message message) void SendToNext(Message message)
{ {
_ = Win32.SendMessageA(_nextClipViewer, (uint)message.Msg, message.WParam, message.LParam); _ = Win32.SendMessageA(_nextClipMonitor, (uint)message.Msg, message.WParam, message.LParam);
} }
switch (m.Msg) { switch (m.Msg) {
case Win32.WM_DRAWCLIPBOARD: case Win32.WM_DRAWCLIPBOARD:
if (_capsLockPressed) { if (_capsLockPressed) {
_capsLockPressed = false; _capsLockPressed = false;
DisplayClipboardData(); TranslateAndShow();
} }
SendToNext(m); SendToNext(m);
break; break;
case Win32.WM_CHANGECBCHAIN: case Win32.WM_CHANGECBCHAIN:
if (m.WParam == _nextClipViewer) { if (m.WParam == _nextClipMonitor) {
_nextClipViewer = m.LParam; _nextClipMonitor = m.LParam;
} }
else { else {
SendToNext(m); SendToNext(m);
@ -96,27 +94,9 @@ internal sealed partial class WinMain : Form
[GeneratedRegex("token: '(\\w+)'")] [GeneratedRegex("token: '(\\w+)'")]
private static partial Regex TokenRegex(); private static partial Regex TokenRegex();
/// <summary> private void InitClipMonitor()
/// 显示剪贴板内容.
/// </summary>
private void DisplayClipboardData()
{ {
var clipText = ClipboardService.GetText(); _nextClipMonitor = Win32.SetClipboardViewer(Handle);
if (clipText.NullOrWhiteSpace()) {
return;
}
_labelDest.Text = Str.Translating;
Task.Run(() => {
var translateText = TranslateText(clipText);
ClipboardService.SetText(translateText);
Invoke(() => { _labelDest.Text = translateText; });
});
var point = Cursor.Position;
point.Offset(new Point(_mouseMargin));
Location = point;
Show();
} }
private void InitForm() private void InitForm()
@ -187,13 +167,35 @@ internal sealed partial class WinMain : Form
Controls.Add(_labelDest); Controls.Add(_labelDest);
} }
private void TranslateAndShow()
{
var clipText = ClipboardService.GetText();
if (clipText.NullOrWhiteSpace()) {
return;
}
_labelDest.Text = Str.Translating;
Task.Run(() => {
var translateText = TranslateText(clipText);
ClipboardService.SetText(translateText);
Invoke(() => { _labelDest.Text = translateText; });
});
var point = Cursor.Position;
point.Offset(new Point(_mouseMargin));
Location = point;
Show();
}
private string TranslateText(string sourceText) private string TranslateText(string sourceText)
{ {
while (true) { while (true) {
var sign = BaiduSignCracker.Sign(sourceText); var sign = BaiduSignCracker.Sign(sourceText);
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"
, CultureInfo.CurrentCulture.TwoLetterISOLanguageName)
, new("query", sourceText) , new("query", sourceText)
, new("simple_means_flag", "3") , new("simple_means_flag", "3")
, new("sign", sign) , new("sign", sign)