在 Node-FFI 中使用 SendInput

2023-12-03

我想使用 Nodejs 中 Windows Api 的 SendInput 函数,使用 FFI 包。

我对 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”,这不应该意味着它可以工作吗?因为我打开记事本时没有按下任何键。


我终于找到了使用方法node-ffi/node-ffi-napi使用以下命令输入按键SendInput功能! (下面的当前代码使用node-ffi-napi, since node-ffi已无人维护/损坏;查看编辑历史记录node-ffi版本,api几乎一模一样)

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

就我而言,我必须使用第二种(扫描代码)方法,因为第一种(虚拟密钥)方法在我需要密钥模拟的程序中不起作用。

废话不多说,完整的解决方案如下:

import keycode from "keycode";
import ffi from "ffi-napi";
import ref from "ref-napi";
import os from "os";
import import_Struct from "ref-struct-di";

var arch = os.arch();
const Struct = import_Struct(ref);

var Input = Struct({
    "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"]],
    MapVirtualKeyExA: ["uint", ["uint", "uint", "int"]],
});

const extendedKeyPrefix = 0xe000;
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 class KeyToggle_Options {
    asScanCode = true;
    keyCodeIsScanCode = false;
    flags?: number;
    async = false; // async can reduce stutter in your app, if frequently sending key-events
}

let entry = new Input(); // having one persistent native object, and just changing its fields, is apparently faster (from testing)
entry.type = INPUT_KEYBOARD;
entry.time = 0;
entry.dwExtraInfo = 0;
export function KeyToggle(keyCode: number, type = "down" as "down" | "up", options?: Partial<KeyToggle_Options>) {
    const opt = Object.assign({}, new KeyToggle_Options(), options);
    
    // scan-code approach (default)
    if (opt.asScanCode) {
        let scanCode = opt.keyCodeIsScanCode ? keyCode : ConvertKeyCodeToScanCode(keyCode);
        let isExtendedKey = (scanCode & extendedKeyPrefix) == extendedKeyPrefix;

        entry.dwFlags = KEYEVENTF_SCANCODE;
        if (isExtendedKey) {
            entry.dwFlags |= KEYEVENTF_EXTENDEDKEY;
        }

        entry.wVK = 0;
        entry.wScan = isExtendedKey ? scanCode - extendedKeyPrefix : scanCode;
    }
    // (virtual) key-code approach
    else {
        entry.dwFlags = 0;
        entry.wVK = keyCode;
        //info.wScan = 0x0200;
        entry.wScan = 0;
    }

    if (opt.flags != null) {
        entry.dwFlags = opt.flags;
    }
    if (type == "up") {
        entry.dwFlags |= KEYEVENTF_KEYUP;
    }

    if (opt.async) {
        return new Promise((resolve, reject)=> {
            user32.SendInput.async(1, entry, arch === "x64" ? 40 : 28, (error, result)=> {
                if (error) reject(error);
                resolve(result);
            });
        });
    }
    return user32.SendInput(1, entry, arch === "x64" ? 40 : 28);
}

export function KeyTap(keyCode: number, opt?: Partial<KeyToggle_Options>) {
    KeyToggle(keyCode, "down", opt);
    KeyToggle(keyCode, "up", opt);
}

export function ConvertKeyCodeToScanCode(keyCode: number) {
    //return user32.MapVirtualKeyExA(keyCode, MAPVK_VK_TO_VSC, 0);
    return user32.MapVirtualKeyExA(keyCode, 0, 0);
}

要使用它,请致电:

KeyTap(65); // press the A key

或者,如果您正在使用关键代码 npm 包:

import keycode from "keycode";
KeyTap(keycode.codes.a);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Node-FFI 中使用 SendInput 的相关文章

  • 从窗口内容截取屏幕截图(无边框)

    我正在寻找有关如何使用 C 将表单内容保存在位图中的解决方案 我已经尝试过使用 DrawToBitmap 但它捕获了所有带边框的窗口 这就是这段代码的结果 public static Bitmap TakeDialogScreenshot
  • 枚举器上的 [[maybe_unused]]

    查看规格 maybe unused http en cppreference com w cpp language attributes 它指出 出现在类 typedef 变量 非静态数据成员 函数 枚举或枚举器的声明中 如果编译器对未使用
  • 如何创建显示/隐藏 Docusaurus 项目中所有详细标签状态的按钮?

    根据讨论here https stackoverflow com questions 58579048 how to add or remove the open attribute from all details tags in a r
  • Lodash _.hasIntersection?

    我想知道两个或多个数组是否有共同的项目 但我不在乎这些项目是什么 我知道 lodash 有一个 intersection方法 但我不需要它来遍历每个数组的每个项目 相反 我需要类似的东西 hasIntersection一旦找到第一个常见的出
  • 如何将类组件中的 props 发送到功能组件?

    我是 ReactJS 的初学者 需要知道如何将一个页面中的 props 值发送到另一个页面 道具位于第一页上我可以获取类组件值如何获取另一页中的值 提前致谢 墙色 jsx import React Component from react
  • 使标签充当输入按钮

    我怎样才能做一个 a href http test com tag test Test a 就像表单按钮一样 通过充当表单按钮 我的意思是 当单击链接执行操作时method get 或 post 以便能够通过 get 或 post 捕获它
  • 如何使用 ReactJS 使表中的列可以以两种方式排序

    我正在 ReactJS 中构建一个简单的应用程序 它通过调用某个 API 来使用 JSON 数组 然后我将数组的结果填充到表中 我现在想让表的列可排序 我理想的情况是同时进行升序和降序排序 一旦我单击标题 当它按升序排序时 它应该按降序排序
  • JavaScript 中的安全数据

    我必须为 Web 测试创建生成器 使用 HTML 和 JavaScript 测试必须离线和在线进行 正确答案和分数评估必须是生成的测试的一部分 最终用户的分数仅发送到服务器 无法在服务器上进行评估 并且服务器对问题一无所知 它只保存最终分数
  • 如何在 MongoDB v3.0.5 中创建用户

    我需要在 mongodb 中为我的数据库创建一个用户 但似乎我无法让它工作 我已经在我的 Windows 7 机器上安装了 mongoDb v3 0 5 根据本文 https docs mongodb org v3 0 tutorial a
  • 带回调或异步/等待的节点 postgres 事务?

    我正在运行 Node 7 6 0 它支持 async await node postgres 客户端池支持 async await 并且有一个很好的示例here https github com brianc node pg pool pl
  • 检查是否安装了 Google Analytics 或 Universal Analytics?

    我正在尝试通过 JavaScript 来确定是否加载了 Google Analytics 或 Universal Analytics 一些客户仍在使用旧的 Google Analytics 我们希望推出一个收集数据的 JavaScript
  • C 的“char”使用什么字符集? [复制]

    这个问题在这里已经有答案了 简单的问题 我最近开始用 C 编程 有一个简单的问题 C 编程语言在其 char 类型中使用什么字符集 例如 ASCII 还是取决于软件 操作系统 char 本质上是 1 个字节 主要在所有操作系统上 所以默认情
  • 跟踪预防阻止了对 https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js 存储的访问

    大约一年半前 我使用 OfficeJS API 编写了一个 Excel 加载项 它一直工作到大约两周前 Excel 似乎已经进行了更新 现在我可以右键单击任务窗格并查看开发工具 而以前我无法做到这一点 并且必须运行外部 MS Edge 开发
  • 反转比例函数

    这对我来说很有趣 看下面的D3代码 var scale d3 scale linear domain 100 500 range 10 350 scale 100 Returns 10 scale 300 Returns 180 scale
  • C 中什么函数可以替换字符串中的子字符串?

    给定一个 char 字符串 我想查找所有出现的子字符串并将其替换为备用字符串 我没有看到任何简单的函数可以实现这一点
  • 使用 NodeJS 创建 YouTube 播放列表

    我正在尝试使用 NodeJS 服务器创建 YouTube 播放列表 我已按照 Oauth 的 NodeJS 快速入门说明进行操作 如以下链接所示 https github com youtube api samples blob maste
  • 单击 html 中的按钮后如何从 javascript 函数写入文件

    我正在尝试编写真正基本的代码 在 html 文件上按下按钮后 通过 JavaScript 函数在本地写入 txt 文件 这不可能吗 我可以仅使用 javascript 文件写入文件 但在尝试同时使用两者时则不能
  • 需要使用 openssl 加密和解密文件的示例 C 代码

    我正在用 Linux C 编写代码 我需要使用以下命令来加密和解密文件 openssl 目前 我使用系统命令 des3 e nosalt k 0123456789012345 in inp file out out file 进行加密 使用
  • JS - 如何将图像对象变成灰度并显示它

    基本上 当单击按钮时 它会告诉移动设备转到相机 一旦相机拍照 它就会给我图像数据 它被称为数据 URL 吗 这是我处理它的代码 var imagesrc data image jpeg base64 imageData var myimag
  • 调用一个从 AngularJS 表达式本地计算值的函数是不是很糟糕?

    我读了关于使用范围的一些 AngularJS 陷阱的文章 http thenittygritty co angularjs pitfalls using scopes 并且它指出您不应在表达式中使用函数 并且我知道每次框架认为需要时都可能会

随机推荐

  • 在 Bash 中 ssh 和运行多个命令的最简洁方法是什么?

    我已经设置了 ssh 代理 并且我可以在 Bash 脚本中的外部服务器上运行命令 执行以下操作 ssh blah server ls pwd 现在 我真正想做的是在外部服务器上运行大量长命令 将所有这些内容括在引号之间会非常难看 而且我真的
  • 如何使用 Red Hat Linux 上的标准工具随机化文件中的行?

    如何使用 Red Hat Linux 上的标准工具随机化文件中的行 我没有shuf命令 所以我正在寻找类似的东西perl or awk完成相同任务的单行 嗯 我们不要忘记 sort random sort
  • 如何使容器在 HTML/CSS 中居中?

    作为我任务的一部分 我开发了一个网站 由于我是 html css 新手 我无法从代码中找出一些问题 分配规范规定屏幕尺寸应在一定尺寸内 以便大多数浏览器都可以打开它 并且用户不应体验到任何滚动活动 所以我用div来划分整个页面以适应大小 但
  • 如何使用 Chrome 扩展程序在页面加载之前隐藏所有内容

    我尝试使用内容脚本 manifest content scripts matches js js content script js content script js ini function ini document body styl
  • SSL 性能影响[重复]

    这个问题在这里已经有答案了 可能的重复 SSL 会产生多少开销 最近 我与一位开发人员进行了交谈 他告诉我 在站点范围内实施 SSL 会使服务器负载增加 300 倍 这真的可信吗 我目前在所有页面上都使用 SSL 每天有数千名用户访问系统
  • 使 HTML 表格单元格中的文本与其他单元格重叠

    我希望单元格中的一些较长文本重叠在下一个单元格中 而不是换行 但又不会使第一列变大 如果我给细胞 white space nowrap position absolute 它将位于正确的位置 但其他文本将在其下方流动 感谢您的快速答复 您可
  • JS 四舍五入到小数点后两位 [重复]

    这个问题在这里已经有答案了 我试图将返回的数字限制为小数点后两位 但此代码对我不起作用 function myFunction var x document getElementById mySelect value document ge
  • 尝试使用 MATLAB 绘制 z = x + y 时出现错误的图形

    我正在尝试在 MATLAB 中绘制 3D 曲面 并且我利用了meshgrid 类似于 MATLAB 教程中所说的 http www mathworks com help matlab ref meshgrid html 我编写了一个非常简单
  • php 正则表达式用目录分隔符替换路径中的“任何”斜杠

    我正在尝试采取这样的路径 一些 路径 这里 一些 其他 路径 并将路径中的每个斜杠替换为 PHP 的 DIRECTORY SEPARATOR 内置常量 我有这个 subject asdf var preg replace DS subjec
  • Firebase 在 Swift 中检索自动 ID 下面的数据

    我在从 Firebase 检索数据时遇到麻烦 我想读取 auto ID 下 JSON 中的所有 contactName 数据 然后附加到 UIPickerView Here is my JSON tree used childByAutoI
  • 接口指定的属性的多态性

    为什么这不起作用 public class ClassOptions public interface Inode ClassOptions Options get public class MyClass Inode public Cla
  • VBScript - 复制过去 24 小时内修改的文件

    我正在尝试从上次修改日期在当前日期 24 小时内的目录中复制文件 我在文件路径中使用通配符 因为它每天都在变化 option explicit dim fileSystem folder file dim path path d x log
  • UIImage 的宝丽来滤镜

    我正在尝试在 iPhone 中实现一些图像滤镜 例如宝丽来 我搜索了如何过滤现有的 UIImage 将其转换为polaroid风格和遇到this堆栈溢出链接 以那里的答案为起点 我循环遍历图像的每个像素 获取 RGB 值 并将它们转换为 H
  • 如何使用 easymock 模拟类中的静态方法?

    假设我有一个像这样的课程 public class StaticDude public static Object getGroove some complex logic which returns an object 如何使用简单模拟来
  • 列表视图内存泄漏

    我有一个带有适配器的简单列表视图 我动态创建了 10 多个列表视图项目 然后我一次又一次地上下滚动 我可以看到可用内存不断减少 我需要在哪里免费以及什么 注意 有一个图像视图 但在我的测试中我没有使用任何图像 所以它是 View GONE
  • 删除边框样式会更改页面布局

    我对以下 HTML CSS 代码有疑问 CSS padding 0 margin 0 border none outline none container margin 10px auto 10px auto width 960px bac
  • 使用javax.swing.Timer在Java中制作倒计时器[重复]

    这个问题在这里已经有答案了 可能的重复 有条件的停止计时器仅在第一次有效 我对如何使用 swing 而不是 util 计时器制作计时器感到非常困惑 我正在制作一款游戏 用户必须在 30 秒的时间内回答问题 我有一个 PlayFrame 其中
  • 选择第一个和最后一个时间戳,其中 userID 是唯一的

    我正在尝试执行查询来获取每个唯一用户的第一个和最后一个时间戳 数据库看起来像这样 ID EventID Timestamp Person Number 1 2 2015 01 08 17 31 40 7 5 2 2 2015 01 08 1
  • 如何“强制”python 使用特定版本的模块?

    我是 python 新手 所以如果这个问题在其他地方用我没有想到的标签得到了回答 我深表歉意 我正在尝试将 numpy 从现在的 1 6 版本更新到 1 8 我已经在我的 python 站点包中安装了 numpy 当我调用 numpy 时
  • 在 Node-FFI 中使用 SendInput

    我想使用 Nodejs 中 Windows Api 的 SendInput 函数 使用 FFI 包 我对 C 的了解有限 所以我无法真正弄清楚我遇到了什么问题 我基本上是想虚拟地按下键盘上的一个键 这就是我的代码 var ffi requi