From 640a92edffaa1d6b0bf32391a73adce29c0f04a2 Mon Sep 17 00:00:00 2001 From: hopechen067 <59017045+hopechen067@users.noreply.github.com> Date: Fri, 2 Oct 2026 04:21:32 -0400 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=8A=8A=20koffi=20=E7=9A=84=20Win?= =?UTF-8?q?32=20=E5=8A=A0=E8=BD=BD=E6=8A=BD=E5=88=B0=E5=85=B1=E7=94=A8?= =?UTF-8?q?=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 粘贴和光标读取共用同一次 user32/kernel32 加载,避免重复定义结构体。 Co-Authored-By: Claude Opus 5.5 --- src/main/paste.js | 54 ++----------------------------- src/main/win32.js | 81 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 52 deletions(-) create mode 100644 src/main/win32.js diff --git a/src/main/paste.js b/src/main/paste.js index 82f19cb..c684d11 100644 --- a/src/main/paste.js +++ b/src/main/paste.js @@ -1,5 +1,7 @@ 'use strict'; +const { loadWin32 } = require('./win32'); + const INPUT_KEYBOARD = 1; const KEYEVENTF_KEYUP = 0x0002; const VK_CONTROL = 0x11; @@ -42,58 +44,6 @@ function writeSnapshot(clipboard, snap) { clipboard.write(payload); } -let win32 = null; - -function loadWin32() { - if (win32) return win32; - if (process.platform !== 'win32') return null; - const koffi = require('koffi'); - const user32 = koffi.load('user32.dll'); - const kernel32 = koffi.load('kernel32.dll'); - - const KEYBDINPUT = koffi.struct('KEYBDINPUT', { - wVk: 'uint16_t', - wScan: 'uint16_t', - dwFlags: 'uint32_t', - time: 'uint32_t', - dwExtraInfo: 'uintptr_t', - }); - const MOUSEINPUT = koffi.struct('MOUSEINPUT', { - dx: 'long', - dy: 'long', - mouseData: 'uint32_t', - dwFlags: 'uint32_t', - time: 'uint32_t', - dwExtraInfo: 'uintptr_t', - }); - const HARDWAREINPUT = koffi.struct('HARDWAREINPUT', { - uMsg: 'uint32_t', - wParamL: 'uint16_t', - wParamH: 'uint16_t', - }); - const INPUT = koffi.struct('INPUT', { - type: 'uint32_t', - u: koffi.union({ - mi: MOUSEINPUT, - ki: KEYBDINPUT, - hi: HARDWAREINPUT, - }), - }); - - win32 = { - koffi, - INPUT, - GetForegroundWindow: user32.func('void * __stdcall GetForegroundWindow()'), - SetForegroundWindow: user32.func('bool __stdcall SetForegroundWindow(void *hWnd)'), - AllowSetForegroundWindow: user32.func('bool __stdcall AllowSetForegroundWindow(uint32_t dwProcessId)'), - GetWindowThreadProcessId: user32.func('uint32_t __stdcall GetWindowThreadProcessId(void *hWnd, _Out_ uint32_t *lpdwProcessId)'), - AttachThreadInput: user32.func('bool __stdcall AttachThreadInput(uint32_t idAttach, uint32_t idAttachTo, bool fAttach)'), - GetCurrentThreadId: kernel32.func('uint32_t __stdcall GetCurrentThreadId()'), - SendInput: user32.func('unsigned int __stdcall SendInput(unsigned int cInputs, INPUT *pInputs, int cbSize)'), - }; - return win32; -} - function captureForeground() { try { const api = loadWin32(); diff --git a/src/main/win32.js b/src/main/win32.js new file mode 100644 index 0000000..d9e0347 --- /dev/null +++ b/src/main/win32.js @@ -0,0 +1,81 @@ +'use strict'; + +let win32 = null; + +function loadWin32() { + if (win32) return win32; + if (process.platform !== 'win32') return null; + const koffi = require('koffi'); + const user32 = koffi.load('user32.dll'); + const kernel32 = koffi.load('kernel32.dll'); + + const KEYBDINPUT = koffi.struct('KEYBDINPUT', { + wVk: 'uint16_t', + wScan: 'uint16_t', + dwFlags: 'uint32_t', + time: 'uint32_t', + dwExtraInfo: 'uintptr_t', + }); + const MOUSEINPUT = koffi.struct('MOUSEINPUT', { + dx: 'long', + dy: 'long', + mouseData: 'uint32_t', + dwFlags: 'uint32_t', + time: 'uint32_t', + dwExtraInfo: 'uintptr_t', + }); + const HARDWAREINPUT = koffi.struct('HARDWAREINPUT', { + uMsg: 'uint32_t', + wParamL: 'uint16_t', + wParamH: 'uint16_t', + }); + const INPUT = koffi.struct('INPUT', { + type: 'uint32_t', + u: koffi.union({ + mi: MOUSEINPUT, + ki: KEYBDINPUT, + hi: HARDWAREINPUT, + }), + }); + + // 64 位默认对齐:两个 DWORD 之后 HWND 从偏移 8 开始,末尾 RECT,共 72 字节。 + const RECT = koffi.struct('RECT', { + left: 'long', + top: 'long', + right: 'long', + bottom: 'long', + }); + const POINT = koffi.struct('POINT', { + x: 'long', + y: 'long', + }); + const GUITHREADINFO = koffi.struct('GUITHREADINFO', { + cbSize: 'uint32_t', + flags: 'uint32_t', + hwndActive: 'void *', + hwndFocus: 'void *', + hwndCapture: 'void *', + hwndMenuOwner: 'void *', + hwndMoveSize: 'void *', + hwndCaret: 'void *', + rcCaret: RECT, + }); + + win32 = { + koffi, + INPUT, + GUITHREADINFO, + GetForegroundWindow: user32.func('void * __stdcall GetForegroundWindow()'), + SetForegroundWindow: user32.func('bool __stdcall SetForegroundWindow(void *hWnd)'), + AllowSetForegroundWindow: user32.func('bool __stdcall AllowSetForegroundWindow(uint32_t dwProcessId)'), + GetWindowThreadProcessId: user32.func('uint32_t __stdcall GetWindowThreadProcessId(void *hWnd, _Out_ uint32_t *lpdwProcessId)'), + AttachThreadInput: user32.func('bool __stdcall AttachThreadInput(uint32_t idAttach, uint32_t idAttachTo, bool fAttach)'), + GetCurrentThreadId: kernel32.func('uint32_t __stdcall GetCurrentThreadId()'), + SendInput: user32.func('unsigned int __stdcall SendInput(unsigned int cInputs, INPUT *pInputs, int cbSize)'), + GetGUIThreadInfo: user32.func('bool __stdcall GetGUIThreadInfo(uint32_t idThread, _Inout_ GUITHREADINFO *pgui)'), + ClientToScreen: user32.func('bool __stdcall ClientToScreen(void *hWnd, _Inout_ POINT *lpPoint)'), + }; + return win32; +} + +module.exports = { loadWin32 };