9
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Windows上のNode.jsでffiを使ってキーボード入力をする

Posted at

いわゆるキーボード入力をエミュレートするというものです。

準備

node-gypが動作する環境を整えておいてください。コンパイル環境は管理者権限のコマンドプロンプトで

npm install --global --production windows-build-tools

と実行すればできるようになります。1

必要なnpmパッケージは次の五つです。それぞれ入れてください。

  • ffi
  • ref
  • ref-struct
  • ref-union
  • ref-array

ffiがDLLを直接読み込んで実行します。refおよびref-*は構造体、共用体、配列などを行うのに必要になります。

コード

面倒だったのでCoffeeScriptで書いています。CoffeeScriptを知らないって人はTry CoffeeScriptで変換されたコードを見てください。2

winkey_send.coffee
import ref from 'ref'
import ffi from 'ffi'
import StructType from 'ref-struct'
import UnionType from 'ref-union'
import ArrayType from 'ref-array'

###
SendInput function
  https://msdn.microsoft.com/library/windows/desktop/ms646310.aspx
###

# check pointer size for defined ULONG_PTR
ptrSize = ref.NULL_POINTER.length
ulongPtr = switch ptrSize
  when 4
    ref.types.uint32
  when 8
    ref.types.uint64
  else
    throw new Error("Supported pointer size is 4 or 8, but is #{ptrSize}")

MouseInputType = StructType
  dx: ref.types.long
  dy: ref.types.long
  mouseData: ref.types.uint32
  dwFlags: ref.types.uint32
  time: ref.types.uint32
  dwExtraInfo: ulongPtr

KeybdInputType = StructType
  wVk: ref.types.uint16
  wScan: ref.types.uint16
  dwFlags: ref.types.uint32
  time: ref.types.uint32
  dwExtraInfo: ulongPtr

HardwareInputType = StructType
  uMsg: ref.types.uint32
  wParamL: ref.types.uint16
  wParamH: ref.types.uint16

UnionInputType = UnionType
  mi: MouseInputType
  ki: KeybdInputType
  hi: HardwareInputType

InputType = StructType
  type: ref.types.uint32
  u: UnionInputType

InputArrayType = ArrayType(InputType)

user32 = ffi.Library 'user32',
  SendInput: [ref.types.uint, [ref.types.uint, InputArrayType, ref.types.int]]

# Virtual-Key Codes
#   https://msdn.microsoft.com/library/windows/desktop/dd375731.aspx
keys = [0x48, 0x4F, 0x47, 0x45] # hoge
inputs = new InputArrayType(keys.length)

for vk, i in keys
  inputs[i].type = 1 # INPUT_KEYBOARD
  inputs[i].u.ki.wVk = vk
  inputs[i].u.ki.wScan = 0
  inputs[i].u.ki.dwFlags = 0
  inputs[i].u.ki.time = 0
  inputs[i].u.ki.dw = 0

setInterval ->
  result = user32.SendInput(inputs.length, inputs, InputType.size)
  console.log("send: #{result}")
, 1000

解説

SendInput関数を使用しています。Cのコードをffiを用いて実現しているだけに過ぎません。

マウスもできると思いますが、試していません。他にもあまりテストしていませんので、うまくいかなかったら、コメント等残してくれると助かります。特に、32bit環境は試す環境が無いので、うまくいくかはかなり不安です。

終了はCtrl+Cなどで強制終了してください。

構造体、共用体、配列が組み合わさった場合にffiにどう読み込ませるかのサンプルが全然見当たらなかったので、本当にこれでいいのかはちょっと不安です。一応、上のコードは手元では動いてはいるのですが。

参考

Node.jsでWindowsのキー状態を取得する
目的は逆ですが、ffiの使い方の参考にさせていただきました。


  1. Python 2.7のインストール先は実行ユーザーのプロファイルになります。インストール時の管理者と実際使うユーザーが異なる場合は手動で準備した方が無難でしょう。 

  2. だれか、ES2015+で整形して書き直したのに置き換えてくれないかな。 

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?