ラズパイにつないだテンキーボードをタクトスイッチ代わりにpythonで使えるようにする（メモ）

[link-01]:https://pypi.org/project/evdev/

#USBテンキーボード
リモートコンソールで実行したpythonプログラムと、ラズパイに物理接続したUSBテンキーボードを連携させて、テンキーを押すとラズパイでプログラムが実行される実験のメモ。

キー入力はpythonで**input()**を使えばできるが、実行しているコンソールの入力を受け付けるので、物理的に接続しているキーデバイスからの入力はできない。

タクトスイッチのように、物理接続のキーボード入力を解釈してなにがしかのコマンドを実行するプログラムを作りたかったので、それを可能にするpythonライブラリ[evdev][link-01]を使って、実験したメモ。

#[evdev][link-01]

冒頭にある記述の通りの機能を持つ。

>This package provides bindings to the generic input event interface in Linux. The evdev interface serves the purpose of passing events generated in the kernel directly to userspace through character devices that are typically located in /dev/input/.

>This package also comes with bindings to uinput, the userspace input subsystem. Uinput allows userspace programs to create and handle input devices that can inject events directly into the input subsystem.

#USBテンキーボード

特にこれというものではなく、値段とメーカーから以下を購入した。使用する機種により、pythonプラグラムでUSBデバイス名は変わるし、キーマップも変わる可能性がある。

[エレコム テンキーボード TK-TCM011BK](https://www.amazon.co.jp/gp/product/B00HL8Z6KS/ref=oh_aui_search_detailpage?ie=UTF8&psc=1)

#デバイスの確認

入力デバイスは**/dev/input/by-id/**をlistすれば分かる。

```shell-session:
ls /dev/input/by-id/
```

表示された**usb-SINO_WEALTH_ELECOM_10KEYBOARD-event-kbd**を、pythonプログラム内で指定する。

```shell-session:
usb-SINO_WEALTH_ELECOM_10KEYBOARD-event-kbd
```

#pythonプラグラム

##参考文献

以下の情報を参考にして、プログラムを作成した。というか、ほぼパクりました。。。

+ [USB Keyboard on Raspberry Pi](http://www.anites.com/2013/12/usb-keyboard-on-raspberry-pi.html)

##ライブラリ

以下のライブラリをラズパイにインストールした。python2.7の場合は**pip3**ではなく**pip**を使う。

+ [evdev][link-01]

```shell-session:
pip3 install evdev
```

##プログラム1

[参考文献](http://www.anites.com/2013/12/usb-keyboard-on-raspberry-pi.html)をほぼパクり、ENTERキーでプログラムを終了するようにした。キーマップは修正している。

キーマップは**keymap.py**に記載しておく。

```py:keymap.py
# keymapping determined by trial and error
keys = {
 79: "1",
 80: "2",
 81: "3",
 75: "4",
 76: "5",
 77: "6",
 71: "7",
 72: "8",
 73: "9",
 82: "0",
 83: ".",
 96: "ENTER",
 78: "+",
 74: "-",
 14: "BS",
 15: "TAB",
 55: "*",
 98: "/",
 # Numlock keys:
 111: "N.",
 110: "N0",
 107: "N1",
 108: "N2",
 109: "N3",
 105: "N4",
 # notice the missing N5
 106: "N6",
 102: "N7",
 103: "N8",
 104: "N9",
}
```

keymap.pyをインポートして、プログラム本体を記述する。

```py:kbtest.py
#coding: utf-8
from evdev import InputDevice
from select import select

from keymap import keys

# look for a /dev/input/by-id/usb...kbd or something similar
DEVICE = "/dev/input/by-id/usb-SINO_WEALTH_ELECOM_10KEYBOARD-event-kbd"

dev = InputDevice(DEVICE)

while True:

    # wait for keypad command
    r, w, x = select([dev], [], [])

    # read keypad        
    for event in dev.read():
        
            if event.type==1 and event.value==1:
                 if event.code in keys:
                    print("KEY     : ", keys[event.code])
                    #print("KEY CODE: ", event.code)

                    # do something with this key press
                    # ...
                    if(event.code == 96): #"ENTER"
                        print("終了します")
                        exit()
                    else:
                        pass

            
```

##プログラム2

[openjtalk](https://qiita.com/teraken_/items/2a41b639c8411a715da0#openjtalk)がインストールされ、ラズパイにスピーカを接続している前提。押したキーをラズパイが読み上げる。ENTERで終了する。

```py:kbtalk.py
#coding: utf-8
from evdev import InputDevice
from select import select

import subprocess

def jtalk(t):
    open_jtalk=['open_jtalk']
    mech=['-x','/var/lib/mecab/dic/open-jtalk/naist-jdic']
    htsvoice=['-m','/usr/share/hts-voice/mei/mei_normal.htsvoice']
    speed=['-r','1.0']
    outwav=['-ow','open_jtalk.wav']
    cmd=open_jtalk+mech+htsvoice+speed+outwav
    c = subprocess.Popen(cmd,stdin=subprocess.PIPE)
    c.stdin.write(t)
    c.stdin.close()
    c.wait()
    aplay = ['aplay','-q','open_jtalk.wav']
    wr = subprocess.Popen(aplay)

from keymap import keys

# look for a /dev/input/by-id/usb...kbd or something similar
DEVICE = "/dev/input/by-id/usb-SINO_WEALTH_ELECOM_10KEYBOARD-event-kbd"

dev = InputDevice(DEVICE)

if __name__ == '__main__':

    while True:

        # wait for keypad command
        r, w, x = select([dev], [], [])

        # read keypad        
        for event in dev.read():
        
            if event.type==1 and event.value==1:
                 if event.code in keys:
                    print("KEY     : ", keys[event.code])
                    #print("KEY CODE: ", event.code)

                    text = str(keys[event.code])
                    jtalk(text.encode('utf-8'))

                    # do something with this key press
                    # ...
                    if(event.code == 96): #"ENTER"
                        text = "終了します"
                        jtalk(text.encode('utf-8'))
                        exit()
                    else:
                        pass
```

event.code別にプログラムを準備することで、物理接続のテンキーボードをタクトスイッチ代わりに使えるようになる。