豆腐とコンソメ

豆腐とコンソメ

もろもろのプログラム勉強記録

Pythonでキーイベントを取得したかったけどできなかった話←できました。

tohutokonsome.hatenablog.com

以前、ラジコンのコントローラーをつくった記事を書きました。

その中で、キーボードから入力した値をもとに操作する機能は、以下の機能を参考にさせていただきました。

qiita.com

ただ、特定キーを押している状態、特定キーを離した状態というイベントを検出できると、よりコントローラぽくなるので、そんなことができる素敵なpythonモジュールがないかを探してました。

その中で、一番よさそうなpythonモジュールを見つけました。
が、想定通りの動作ができていないです。
解決策が見つけたら書くぞ!という意気込みを兼ねて、一旦記事に起こします。

pynput

キーボードやマウスを制御したり、入力内容の監視がシンプルにできるみたい。
キーロガーとかで使ったりするのかしら。
pypi.python.org

実行環境とインストー

(raspberry_3.5.1) masao-3:keyboard konoe_mario$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.10.5
BuildVersion:   14F1713

(raspberry_3.5.1) masao-3:keyboard konoe_mario$ pyenv versions
  system
  3.5.1
  3.5.1/envs/raspberry_3.5.1
  3.5.2
  pypy3-2.4.0
* raspberry_3.5.1 (set by /Users/konoe_mario/.pyenv/version)

(raspberry_3.5.1) masao-3:keyboard konoe_mario$ sudo pip install pynput

サンプルコード

公式サイトの入力内容の監視を行うmサンプルコードをそのまま使用。
キー入力をlistenerがキャッチしてくれて、キー入力が行われると、on_pressに設定した関数を呼んで、キーが離されるとon_releaseに設定した関数が呼ばれる。

from pynput.keyboard import Key, Listener

def print_something():
'''
デバック用
'''
    print('hi tohu!')

def on_press(key):
    #この関数が呼ばれているかどうかチェックするための処理
    print_something()

    try:
        print('alphanumeric key {0} pressed'.format(
            key.char))
    except AttributeError:
        print('special key {0} pressed'.format(
            key))


def on_release(key):
    print('{0} released'.format(key))

    if key == Key.esc:
        # Stop listener
        return False

if __name__ == '__main__':

    with Listener(
        on_press = on_press,
        on_release= on_release
    ) as listener:
        listener.join()

動かない

上記サンプルコードを、ターミナルで実行すると、「Command」「Shift」「Control」「option」などの入力は検知するのだけれども、通常の英数字のキー入力は検知してくれていない。

StackOverFlowにすごくそれっぽい質問もあがってたのだけれども、どうも原因が違うのではないかと思う。

stackoverflow.com

そもそも、on_press関数内のprint関数が英数字の場合は呼ばれていない。

(raspberry_3.5.1) masao-3:keyboard konoe_mario$ python pynput_sample.py 

(raspberry_3.5.1) masao-3:keyboard konoe_mario$ python pynput_sample.py 
##キー入力を検知すると、on_press内の「hi tohu」が出力される
hi tohu!
special key Key.cmd pressed
Key.cmd released
hi tohu!
special key Key.alt pressed
Key.alt released
hi tohu!
special key Key.shift pressed
Key.shift released
hi tohu!
special key Key.ctrl pressed
Key.ctrl released

##こっから下は英数字の入力を行ったところ
1111
111
ugokanai
^[^[^[
^[[A

英数字の場合、コンソールに普通に入力できてしまうので、スペシャルキーとは挙動が違うのかもしれない。
ただ、StackOverFlowの質問を見る限り、特になんの制御もなくできてるっぽいんですよね。。。

sudoが足りなかった

sudo実行で普通にできました。Kさん、ありがとうございました。

(raspberry_3.5.1) masao-3:keyboard konoe_mario$ sudo python pynput_sample.py 
Password:
hi tohu!
alphanumeric key None pressed
a<0> released
hi tohu!
alphanumeric key None pressed
s<1> released
hi tohu!
alphanumeric key None pressed
d<2> released
hi tohu!
alphanumeric key None pressed
f<3> released

よくみるとKeyCodeを認識していない

うまくいってませんでした。。。
デバックでいろいろ見ていたのですが、OSXのキー入力のあたりから調べないとちょっと厳しそう。
進展がありしだい追記します。

(raspberry_3.5.1) masao-3:keyboard konoe_mario$ sudo python pynput_sample.py 
Password:
alphanumeric key None pressed ←押されたキー入力がNoneになっている。

2017.7.12追記

久しぶりに別件で起動してたら、KeyCodeを認識していることに気づいた。 なぜだろう。。。

(raspberry_3.5.1) masao-3:keyboard konoe_mario$ sudo python  pynput_sample.py 
alphanumeric key <13> pressed
w<13> released
alphanumeric key <1> pressed
s<1> released
alphanumeric key <0> pressed
a<0> released
alphanumeric key <2> pressed
d<2> released

その他候補

すっごい適当だけれども、pynput以外に試したものを、メモがてらに記載しています。

msvrct

Windowsでしか動かないので、採用しなかった。

keyboard

ホットキーの設定をしたり、キーイベントの監視をしたりいろいろとできそうだった。

pypi.python.org

が実行するとOSErrorになる。

OSError: [Errno 45] Operation not supported: '/dev/uinput'

公式をよく読んでみると、ちゃんと書いてありました。
「Hook and simulate keyboard events on Windows and Linux

Pygame

pythonのゲーム開発向けのモジュール。
導入するだけしてみたけれども、今回やりたいことだけにしては、大掛かりな印象を持った。
GUI画面を用いてコントローラーにするのには、いいのかもしれない。
でも、python3.5.1では、キー入力のイベント検知が動かなかった。

PySDL2

Pygameの後継らしい。
こっちではpython3.5.1でもキー入力イベントを検知することができた。