using SendInput in Node-FFI

懵懂的女人 提交于 2019-12-08 12:31:08

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!