npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

myde-input

v1.0.1

Published

High-performance Linux input device reader

Readme

myde-input

高性能 Linux 输入设备读取库,采用 Rust + TypeScript 混合架构。

通过 Rust 直接访问 Linux evdev 接口,以 MessagePack 二进制协议与 Node.js 通信,提供事件驱动的输入设备管理 API。

特性

  • 高性能:Rust 侧使用 epoll 非阻塞 I/O 直接读取 /dev/input/event*,零拷贝事件传递
  • 设备扫描:自动扫描并识别所有输入设备,支持键盘、鼠标、触摸板、触屏、数位板、手柄
  • 多点触控:完整支持 Multi-touch Protocol A 和 B,包含位置、压力、方向、跟踪 ID、槽位等详细触控轴信息
  • 键码映射:内置完整的 Linux evdev 键码常量表,支持 Web 键码 <-> Linux 键码双向映射
  • 类型安全:TypeScript strict 模式,完整的类型定义与泛型 Result 错误处理(无 throw)
  • 事件驱动:基于 EventEmitter 的 API,支持 keyDown/keyUp/relative/absolute/sync 等语义事件
  • 设备能力检测:通过 ioctl 读取设备的事件类型、按键、相对轴、绝对轴等能力信息
  • 错误容错:Rust 风格的 Result<T, E> 类型,设备操作失败不会抛出异常,错误信息结构化返回
  • 跨平台构建:CI/CD 支持 x86_64 和 aarch64 Linux 交叉编译

安装

npm install myde-input
# 或
pnpm add myde-input

前置条件:需要 Linux 系统,且进程有访问 /dev/input/event* 设备的权限(通常需要加入 input 用户组或以 root 运行)。

快速开始

import { InputManager } from "myde-input";

const manager = new InputManager();

// 初始化(启动 Rust 子进程)
const initResult = await manager.init();
if (!initResult.ok) {
  console.error("初始化失败:", initResult.error);
  process.exit(1);
}

// 监听设备添加
manager.on("deviceAdded", (device) => {
  console.log(`发现设备: ${device.name} (${device.type}) → ${device.path}`);

  const dev = manager.getDevice(device.path);
  if (!dev) return;

  // 开始读取事件
  const readResult = dev.startReading();
  if (!readResult.ok) {
    console.error("开始读取失败:", readResult.error);
    return;
  }

  // 监听键盘事件
  dev.on("keyDown", (code) => {
    console.log(`按键按下: ${code}`);
  });

  dev.on("keyUp", (code) => {
    console.log(`按键释放: ${code}`);
  });

  // 监听鼠标相对移动
  dev.on("relative", (code, value) => {
    console.log(`相对移动: axis=${code}, value=${value}`);
  });

  // 监听原始事件
  dev.on("raw", (event) => {
    console.log(`原始事件: type=${event.type}, code=${event.code}, value=${event.value}`);
  });
});

// 监听设备移除
manager.on("deviceRemoved", (path) => {
  console.log(`设备移除: ${path}`);
});

// 监听错误
manager.on("error", (error) => {
  console.error(`错误 [${error.code}]: ${error.message}`);
});

API

InputManager

设备管理器,负责 Rust 子进程生命周期和设备发现。

const manager = new InputManager();

await manager.init(): Result<void>       // 初始化,启动子进程
manager.getDevices(): DeviceInfo[]       // 获取所有已发现设备
manager.getDevice(path): InputDevice     // 按路径获取单个设备
manager.isInitialized(): boolean         // 检查是否已初始化
await manager.destroy(): void            // 销毁管理器,停止子进程

// 事件
manager.on("deviceAdded", (info) => { ... })
manager.on("deviceRemoved", (path) => { ... })
manager.on("error", (error) => { ... })

InputDevice

单个输入设备的封装,提供事件读取和语义事件分发。

const dev = manager.getDevice("/dev/input/event0");

dev.info: DeviceInfo                     // 设备信息
dev.startReading(): Result<void>         // 开始读取事件
dev.stopReading(): Result<void>          // 停止读取事件
dev.isReading(): boolean                 // 是否正在读取
dev.destroy(): void                      // 销毁设备

// 语义事件
dev.on("key", (code, value, timestamp) => { ... })  // 任意键事件 (value: 0=释放, 1=按下, 2=重复)
dev.on("keyDown", (code) => { ... })                 // 键按下
dev.on("keyUp", (code) => { ... })                   // 键释放
dev.on("keyRepeat", (code) => { ... })               // 键重复
dev.on("relative", (code, value) => { ... })         // 相对轴 (鼠标移动)
dev.on("absolute", (code, value) => { ... })         // 绝对轴 (触屏/摇杆)
dev.on("sync", () => { ... })                        // 同步事件
dev.on("raw", (event) => { ... })                    // 原始 InputEvent
dev.on("error", (error) => { ... })                  // 错误

Result<T, E>

Rust 风格的错误处理类型,避免使用 throw/try-catch。

import { ok, okVoid, err, ErrorCode } from "myde-input";

const result: Result<number> = ok(42);
if (result.ok) {
  console.log(result.value);  // 42
} else {
  console.error(result.error.code, result.error.message);
}

键码常量

import { KEY_A, KEY_ENTER, BTN_LEFT, ABS_MT_POSITION_X } from "myde-input/dist/codes.js";

架构

┌─────────────────────────────────────────────────────┐
│  Node.js 进程                                        │
│  ┌─────────────┐  ┌──────────────┐  ┌────────────┐  │
│  │ InputManager│──│  RustBridge  │──│  msgpackr  │  │
│  │ InputDevice │  │ (subprocess) │  │ (encode/   │  │
│  │ EventEmitter│  │              │  │  decode)   │  │
│  └─────────────┘  └──────┬───────┘  └────────────┘  │
│                          │ stdin/stdout              │
│                    ┌─────┴──────┐                    │
│                    │ 4-byte len │                    │
│                    │ + msgpack  │                    │
│                    └────────────┘                    │
└──────────────────────────┬──────────────────────────┘
                           │
┌──────────────────────────┴──────────────────────────┐
│  Rust 子进程 (myde-input-reader)                     │
│  ┌──────────┐  ┌──────────┐  ┌───────────────────┐  │
│  │ scanner  │  │ reader   │  │ device_info       │  │
│  │ /proc/   │  │ epoll    │  │ ioctl EVIOCGBIT   │  │
│  │ bus/     │  │ 非阻塞   │  │ EVIOCGABS         │  │
│  │ input/   │  │ 多设备   │  │ 能力检测          │  │
│  │ devices  │  │ 事件循环 │  │                   │  │
│  └──────────┘  └──────────┘  └───────────────────┘  │
│                          │                           │
│                    /dev/input/event*                 │
└─────────────────────────────────────────────────────┘

CLI 工具

项目附带一个类似 evtest 的命令行工具,用于交互式查看输入设备和实时事件。

# 列出所有输入设备
npx tsx cli.ts list

# 列出所有设备(含未知类型)
npx tsx cli.ts list --all

# 查看设备详细能力
npx tsx cli.ts info /dev/input/event0

# 实时监听事件(交互选择设备)
npx tsx cli.ts monitor

# 监听指定设备
npx tsx cli.ts monitor /dev/input/event0

# 只看键盘事件
npx tsx cli.ts monitor --event=key

# 只看鼠标移动和按键
npx tsx cli.ts monitor /dev/input/event3 --event=key,rel

注意:监听设备事件需要访问 /dev/input/event* 的权限。通常需要将用户加入 input 组(sudo usermod -aG input $USER)或以 root 运行。

开发

详见 AGENTS.md。

许可证

AGPL-3.0-only