javascript - 节点 ffi SetWindowsHookExW KeyboardProc 回调不适用于 32 位
问题描述
此代码在 x64 上运行良好(它是键盘输入事件的单独线程中的 windows 全局挂钩。在电子程序中使用它来实现条形码扫描功能),即 KBDLLHOOKSTRUCT 结构中的 keyboardPoc 接收器正确值:vkCode、scanCode 等。但是在 x86 上不是 - 任何按键总是有相同的值。我认为问题出在结构数据类型中并以不同的方式更改它们,但没有任何帮助。我一遍又一遍地测试了结果,所以我需要社区的帮助。
const os = require("os");
const ffi = require("ffi-napi");
const ref = require("ref-napi");
const Struct = require("ref-struct-di")(ref);
const is64bit = os.arch() === "x64";
// Types
const LONG = is64bit ? ref.types.long : ref.types.int32;
const ULONG = is64bit ? ref.types.ulong : ref.types.uint32;
const INT = ref.types.int;
const UINT = ref.types.uint;
const DWORD = ref.types.uint32; // DWORD always is unsigned 32-bit
const BOOL = ref.types.bool;
const HANDLE = is64bit ? ref.types.uint64 : ref.types.uint32;
const HHOOK = HANDLE;
const HWND = HANDLE;
const HINSTANCE = HANDLE;
const WPARAM = is64bit ? ref.types.uint64 : ref.types.uint32; // typedef UINT_PTR, uint32(x86) or uint64(64)
const LPARAM = is64bit ? ref.types.int64 : ref.types.int32; // typedef LONG_PTR, int32(x86) or int64(64)
const LRESULT = is64bit ? ref.types.int64 : ref.types.int32; // typedef LONG_PTR
const HOOKPROC = "pointer";
// Structures
const POINT = Struct({
x: LONG,
y: LONG,
});
const MSG = Struct({
hwnd: HWND,
message: UINT,
wParam: WPARAM,
lParam: LPARAM,
time: DWORD,
pt: POINT,
lPrivate: DWORD,
});
const KBDLLHOOKSTRUCT = Struct({
vkCode: DWORD,
scanCode: DWORD,
flags: DWORD,
time: DWORD,
dwExtraInfo: ULONG,
});
// User32 bindings
const user32 = ffi.Library("user32", {
SetWindowsHookExW: [HHOOK, [INT, HOOKPROC, HINSTANCE, DWORD]],
UnhookWindowsHookEx: [BOOL, [HHOOK]],
CallNextHookEx: [LRESULT, [HHOOK, INT, WPARAM, LPARAM]],
GetMessageW: [BOOL, [MSG, HWND, UINT, UINT]],
TranslateMessage: [BOOL, [MSG]],
DispatchMessageW: [LRESULT, [MSG]],
});
// Constants
const WH_KEYBOARD_LL = 13;
const WM_KEYDOWN = 0x0100; // 256
// const WM_KEYUP = 0x0101; // 257
// const WM_SYSKEYDOWN = 0x0104; // 260
// const WM_SYSKEYUP = 0x0105; // 261
let hHook = 0;
// Callback for LL(low-level) hook (doesn`t require dll injection)
// LRESULT CALLBACK LowLevelKeyboardProc(
// _In_ int nCode,
// _In_ WPARAM wParam,
// _In_ LPARAM lParam
// );
const keyboardProc = ffi.Callback(
LRESULT,
[INT, WPARAM, KBDLLHOOKSTRUCT],
(nCode, wParam, lParam) => {
console.log(
`input event callback: ${JSON.stringify(nCode)} ${JSON.stringify(
wParam
)} ${JSON.stringify(lParam)}`
);
if (wParam === WM_KEYDOWN) {
const message = {
event: "key-down",
data: {
vkCode: lParam.vkCode,
scanCode: lParam.scanCode,
},
};
}
return user32.CallNextHookEx(
hHook,
nCode,
wParam,
ref.address(lParam.ref())
);
}
);
/* Set the hook */
hHook = user32.SetWindowsHookExW(WH_KEYBOARD_LL, keyboardProc, 0, 0);
/* Message loop */
const msg = new MSG();
const res = user32.GetMessageW(msg.ref(), 0, 0, 0);
while (res) {
user32.TranslateMessage(msg.ref());
user32.DispatchMessageW(msg.ref());
}
解决方案
正确的类型keyboardProc
必须是[INT, WPARAM, ref.refType(KBDLLHOOKSTRUCT)]
。然后lParam.deref()
显示正确的价值。感谢https://stackoverflow.com/a/69688272/11492379的低端,这对我有很大帮助。
推荐阅读
- python - 无法使用 ffmpeg 或 moviepy 将视频转换为音频
- algorithm - 3路分区快速排序稳定吗?
- python - 使用随机、字符串、迭代器生成随机密码并将其写入文本文件
- javascript - 如何在 vuejs 中为 v-input-field 添加占位符?
- javascript - 安装基于接口的对象
- typescript - vue3/typescript + d3.js: ComputeRef 类型的参数
未分配给可迭代 - java - 如何在 iOS 设备的 Flutter 中集成 Razorpay Payment
- python - Pandas 中按范围排列的频率表返回 1 或 0
- python - 有什么方法可以在python for循环中编写(对于A中的len-1 :)
- google-sheets - 有没有办法在 GoogleSheet 方程中使用动态数据范围,以适应导入的 csv 数据?