问题
I wanted to use the SendInput function from the windows Api in nodejs, using the FFI package.
My knowledge of C is limited so I can't really figure out what problem I have, I'm basically trying to Virtually press a key on the keyboard.
That's the code I have:
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);
It logs me a "1" in the console, shouldn't that mean it works? Because I don't get a key pressed when I open notepad.
回答1:
I finally found a way to use node-ffi to input key-presses using the SendInput function!
However, note that there are two ways you can call the SendInput function, as seen here: https://autohotkey.com/boards/viewtopic.php?p=213617#p213617
In my case, I had to use the second (scan code) approach, because the first (virtual key) approach didn't work in the game I needed the key simulation for. So, calling the function with asScanCode = false
hasn't been tested yet.
Without further ado, here is the complete solution:
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);
}
To use it, call:
KeyTap(65); // press the A key
Or, if you're using the keycode npm package:
import keycode from "keycode";
KeyTap(keycode.codes.a);
回答2:
The "1" tells you that 1 event was inserted, not what the event actually is. I don't know about FFI but it seems to me that keyboardInput has some invalid type definitions. wVK and wScan must be 16-bit integers (hence the 'w' for WORD). Since they are typed the same as dwFlags (an 'int') that's cause invalid input values.
来源:https://stackoverflow.com/questions/41350341/using-sendinput-in-node-ffi