在Node-FFI中使用SendInput

我想使用FFI包从nodejs中的Windows Api使用SendInput函数。

我对C的了解是有限的,所以我无法弄清楚我有什么问题,我基本上是试图按键盘上的键。

那是我的代码:

var ffi = require('ffi'); var ref = require ('ref'); var struct = require ('ref-struct'); var keyboardInput = struct({ 'type': 'int', 'wVK': 'int', 'wScan': 'int', 'dwFlags': 'int', 'time': 'int', 'dwExtraInfo': 'int64' }); var keyboardInputPtr = ref.refType(keyboardInput); var keyboard = new keyboardInput(); keyboard.type = 1; keyboard.wVK = 0x41; keyboard.wScan = 0; keyboard.dwFlags = 2; keyboard.time = 0; keyboard.dwExtraInfo = 0; var user32 = ffi.Library('user32', { 'SendInput': [ 'int', [ 'uint', keyboardInputPtr, 'int' ] ] }); setInterval(function(){ var r = user32.SendInput(1, keyboard.ref(), 40); console.log(r); }, 500); 

它在控制台中记录了一个“1”,这不应该意味着它有效吗? 因为打开记事本时我没有按下按键。

“1”告诉您插入了1个事件,而不是事件的实际内容。 我不知道FFI,但在我看来,keyboardInput有一些无效的类型定义。 wVK和wScan必须是16位整数(因此WORD为’w’)。 因为它们的输入类型与导致无效输入值的dwFlags(’int’)相同。

我终于找到了一种方法来使用node-ffi来使用SendInput函数输入按键!

但请注意,有两种方法可以调用SendInput函数,如下所示: https ://autohotkey.com/boards/viewtopic.php?p = 213617#p213617

在我的情况下,我不得不使用第二种(扫描码)方法,因为第一种(虚拟键)方法在我需要关键模拟的游戏中不起作用。 因此,使用asScanCode = false调用该函数尚未经过测试。

不用多说,这是完整的解决方案:

 import ffi from "ffi"; import ref from "ref"; import StructType from "ref-struct"; var arch = require("os").arch(); var intPtr = ref.refType("int"); var Input = StructType({ "type": "int", // For some reason, the wScan value is only recognized as the wScan value when we add this filler slot. // It might be because it's expecting the values after this to be inside a "wrapper" substructure, as seen here: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx "???": "int", "wVK": "short", "wScan": "short", "dwFlags": "int", "time": "int", "dwExtraInfo": "int64" }); var user32 = ffi.Library("user32", { SendInput: ["int", ["int", Input, "int"]], //MapVirtualKeyEx: ["uint", ["uint", "uint", intPtr]], }); function ConvertKeyCodeToScanCode(keyCode: number) { let keys = "**1234567890-=**qwertyuiop[]**asdfghjkl;'`*\\zxcvbnm,./".split(""); return keys.indexOf(String.fromCharCode(keyCode).toLowerCase()); } const INPUT_KEYBOARD = 1; const KEYEVENTF_EXTENDEDKEY = 0x0001; const KEYEVENTF_KEYUP = 0x0002; const KEYEVENTF_UNICODE = 0x0004; const KEYEVENTF_SCANCODE = 0x0008; const MAPVK_VK_TO_VSC = 0; export function KeyToggle(keyCode: number, type = "down" as "down" | "up", asScanCode = true) { let entry = new Input(); entry.type = INPUT_KEYBOARD; entry.time = 0; entry.dwExtraInfo = 0; // (virtual) key-code approach if (!asScanCode) { entry.dwFlags = type == "down" ? 0 : KEYEVENTF_KEYUP; entry.wVK = keyCode; entry.wScan = 0; } // scan-code approach else { //let scanCode = user32.MapVirtualKeyEx(keyCode, MAPVK_VK_TO_VSC); // this should work, but it had a Win32 error (code 127) for me let scanCode = ConvertKeyCodeToScanCode(keyCode); entry.dwFlags = type == "down" ? KEYEVENTF_SCANCODE : KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP; entry.wVK = 0; entry.wScan = scanCode; } let result = user32.SendInput(1, entry, arch === "x64" ? 40 : 28); console.log(`Number of key-events added: ${result}`); } export function KeyTap(keyCode: number, asScanCode = true) { KeyToggle(keyCode, "down", asScanCode); KeyToggle(keyCode, "up", asScanCode); } 

要使用它,请致电:

 KeyTap(65); // press the A key 

或者,如果您使用的是密码npm包 :

 import keycode from "keycode"; KeyTap(keycode.codes.a);