Edited at

Pythonでバックグラウンド実行中にキー入力を取得する(windows)

More than 1 year has passed since last update.


はじめに

あまり需要はないのかもしれませんが,バックグラウンド実行中(つまりPythonアプリにフォーカスがあっていない状態)のキー入力を取得したい時が稀にあります.JavaにはJNativeHookというライブラリがあり使い勝手もそこそこ良いのですが,それだけのためにJavaを使うのもな,,,,と思いPythonでやる方法を模索した結果,どん詰まりしたので備忘録を残しておきます.


環境


  • Windows8 (10)

  • Python3.6.0


PyHookなるものがあるものの...

まず調べて色々なところで引っかかったのが,PyHookを使う方法.

バックグラウンドで動いて,キーダウン,キーアップ等のイベントがとれるらしい(おもしろ雑感- pyHookについてコケたところ).

早速試してみようと,http://www.lfd.uci.edu/~gohlke/pythonlibs からpyHookの対応するバージョンを落としてきて,

wheel install pyHook‑1.5.1‑cp36‑cp36m‑win_amd64.whl

でインストール(バージョン問題等で非常に手間取った).

from pyHook import HookManager

from win32gui import PumpMessages, PostQuitMessage

class Keystroke_Watcher(object):
def __init__(self):
self.hm = HookManager()
self.hm.KeyDown = self.on_keyboard_event
self.hm.HookKeyboard()

def on_keyboard_event(self, event):
try:
print ('MessageName:',event.MessageName)
print ('Ascii:', repr(event.Ascii), repr(chr(event.Ascii)))
print ('Key:', repr(event.Key))
print ('KeyID:', repr(event.KeyID))
print ('ScanCode:', repr(event.ScanCode))
print ('Time:',event.Time)
print ('-'*5)
finally:
return True

def your_method(self):
pass

def shutdown(self):
PostQuitMessage(0)
self.hm.UnhookKeyboard()

watcher = Keystroke_Watcher()
PumpMessages()

を実行してみたものの,Emacs, SublimeTextを使っているときは問題なく動くが,chromeブラウザ上でキーを叩くと落ちるという謎事態に.エラーとしては

TypeError: KeyboardSwitch() missing 8 required positional arguments: 'msg', 'vk_code', 'scan_code', 'ascii', 'flags', 'time', 'hwnd', and 'win_name'

のようなもので,調べていったっ結果,どうやらPython3系にて実行した時に発生するバグらしく(https://stackoverflow.com/questions/26156633/pythoncom-crashes-on-keydown-when-used-hooked-to-certain-applications ),お手上げ状態.


PyHooked

なにかいい代替手段が見つからないかさがしていたところ,pyHookedなるものをみつけました.

インストールは

pip install pyhooked

で行い,Githubページのexample.pyにあるように,

from pyhooked import Hook, KeyboardEvent, MouseEvent

def handle_events(args):
if isinstance(args, KeyboardEvent):
print(args.key_code, args.current_key, args.event_type)

if isinstance(args, MouseEvent):
print(args.mouse_x, args.mouse_y)

hk = Hook() # make a new instance of PyHooked
hk.handler = handle_events # add a new shortcut ctrl+a, or triggered on mouseover of (300,400)
hk.hook() # hook into the events, and listen to the presses

イベントハンドラを作成してあげることで,キーボード,マウスの入力がバックグラウンドで簡単に取れるようになります.


参考