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))]
[Localization(typeof(Str))]
[SupportedOSPlatform(nameof(OSPlatform.Windows))]
// ReSharper disable once ClassNeverInstantiated.Global
internal sealed class Main : ToolBase<Option>
{
protected override Task Core()

View File

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

View File

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

View File

@ -1,7 +1,7 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable UnusedMethodReturnValue.Global
#pragma warning disable SA1307
#pragma warning disable SA1307, SX1309
using System.Runtime.InteropServices;
@ -30,59 +30,69 @@ internal static partial class Win32
public delegate nint HookProc(int nCode, nint wParam, nint lParam);
[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)]
[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)]
internal static partial int GetClassLongA(nint hWnd, int nIndex);
public static partial int GetClassLongA(nint hWnd, int nIndex);
[LibraryImport(_KERNEL32_DLL)]
internal static partial nint GetConsoleWindow();
public static partial nint GetConsoleWindow();
[LibraryImport(_USER32_DLL)]
internal static partial nint GetDesktopWindow();
public static partial nint GetDesktopWindow();
[LibraryImport(_KERNEL32_DLL, StringMarshalling = StringMarshalling.Utf16)]
internal static partial nint GetModuleHandleA(string lpModuleName);
public static partial nint GetModuleHandleA(string lpModuleName);
[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)]
internal static partial nint GetWindowDC(nint hWnd);
public static partial nint GetWindowDC(nint hWnd);
[LibraryImport(_USER32_DLL)]
internal static partial int ReleaseDC(nint hWnd, nint dc);
public static partial int ReleaseDC(nint hWnd, nint dc);
[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);
[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)]
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)]
internal static partial int SetClipboardViewer(nint hWnd);
public static partial int SetClipboardViewer(nint hWnd);
[LibraryImport(_KERNEL32_DLL)]
internal static partial void SetLocalTime(Systemtime st);
public static partial void SetLocalTime(Systemtime st);
[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)]
[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)]
[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)]
public struct InputStruct
@ -91,29 +101,19 @@ internal static partial class Win32
[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;
[FieldOffset(20)] private readonly long _; // 补位以匹配 UNION的MOUSEINPUT参数 28bytes
[FieldOffset(12)] private readonly nint dwExtraInfo;
[FieldOffset(8)] private readonly uint time;
[FieldOffset(2)] private readonly ushort wScan;
}
[StructLayout(LayoutKind.Explicit)]
internal ref struct Systemtime
public ref struct Systemtime
{
[FieldOffset(6)] public ushort wDay;
[FieldOffset(4)] public ushort wDayOfWeek;

View File

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

View File

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

View File

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

View File

@ -14,19 +14,18 @@ namespace Dot.Tran;
[SupportedOSPlatform(nameof(OSPlatform.Windows))]
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_HOME_URL = "https://fanyi.baidu.com";
private readonly HttpClient _httpClient = new();
private readonly KeyboardHook _keyboardHook = new();
private readonly Label _labelDest = new(); // 显示翻译内容的文本框
private readonly Label _labelDest = 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 _disposed;
private nint _nextClipViewer; // 下一个剪贴板监视链对象句柄
private string _token = "ae72ebad4113270fd26ada5125301268";
private nint _nextClipMonitor; // 下一个剪贴板监视链对象句柄
private string _token = "ae72ebad4113270fd26ada5125301268"; // 翻译api token
public WinMain()
{
@ -34,8 +33,7 @@ internal sealed partial class WinMain : Form
InitHook();
InitLabelDest();
InitHttpClient();
_nextClipViewer = Win32.SetClipboardViewer(Handle);
InitClipMonitor();
}
~WinMain()
@ -58,7 +56,7 @@ internal sealed partial class WinMain : Form
_keyboardHook?.Dispose();
}
Win32.ChangeClipboardChain(Handle, _nextClipViewer); // 从剪贴板监视链移除本窗体
Win32.ChangeClipboardChain(Handle, _nextClipMonitor); // 从剪贴板监视链移除本窗体
_disposed = true;
}
@ -66,21 +64,21 @@ internal sealed partial class WinMain : Form
{
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) {
case Win32.WM_DRAWCLIPBOARD:
if (_capsLockPressed) {
_capsLockPressed = false;
DisplayClipboardData();
TranslateAndShow();
}
SendToNext(m);
break;
case Win32.WM_CHANGECBCHAIN:
if (m.WParam == _nextClipViewer) {
_nextClipViewer = m.LParam;
if (m.WParam == _nextClipMonitor) {
_nextClipMonitor = m.LParam;
}
else {
SendToNext(m);
@ -96,27 +94,9 @@ internal sealed partial class WinMain : Form
[GeneratedRegex("token: '(\\w+)'")]
private static partial Regex TokenRegex();
/// <summary>
/// 显示剪贴板内容.
/// </summary>
private void DisplayClipboardData()
private void InitClipMonitor()
{
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();
_nextClipMonitor = Win32.SetClipboardViewer(Handle);
}
private void InitForm()
@ -187,13 +167,35 @@ internal sealed partial class WinMain : Form
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)
{
while (true) {
var sign = BaiduSignCracker.Sign(sourceText);
var content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>> {
new("from", "auto")
, new("to", "zh")
, new( //
"to"
, CultureInfo.CurrentCulture.TwoLetterISOLanguageName)
, new("query", sourceText)
, new("simple_means_flag", "3")
, new("sign", sign)