West Gate Laboratory

人生を少しでも,面白く便利にするモノづくり

python3にもkbhit()とgetch()が欲しい

はじめに

何言語でプログラミングするにしろ、ユーザからのキーボード入力はよく使うだろう。 特によく使う方法は「通常はメインの処理をしていて、キーボード入力が何かあったときだけ、そのキーに応じて別の処理をする」というものである。 私はよくPICなどを使って電子工作しているが、そういったデバイスではあまり文字列処理はしない。1文字で十分である。

すなわち、kbhit()+getch()である。これさえあればOK。

最近はラズパイでpythonを使っているが、ラズパイでもそういった処理をする方法を紹介する。

kbhit.pyというものがある

やっぱりこういうことは誰でもやりたいと思うからか、ライブラリを作って公開してくれている人がいるので、それをありがたく使わせてもらう。

code.activestate.com

ただ、これをpython3でそのまま実行しようとすると以下のようなエラーが出る。

  File "recipe-572182-1.py", line 33
    return dr <> []
               ^
SyntaxError: invalid syntax

この「<>」はpythonのnot equalの記号だが、python3では文法エラーになるようなので、それを修正したコードをここに書いておく。(といっても<>を!=に修正しただけ)

import sys, termios, atexit
from select import select

# save the terminal settings
fd = sys.stdin.fileno()
new_term = termios.tcgetattr(fd)
old_term = termios.tcgetattr(fd)

# new terminal setting unbuffered
new_term[3] = (new_term[3] & ~termios.ICANON & ~termios.ECHO)

# switch to normal terminal
def set_normal_term():
    termios.tcsetattr(fd, termios.TCSAFLUSH, old_term)

# switch to unbuffered terminal
def set_curses_term():
    termios.tcsetattr(fd, termios.TCSAFLUSH, new_term)

def putch(ch):
    sys.stdout.write(ch)

def getch():
    return sys.stdin.read(1)

def getche():
    ch = getch()
    putch(ch)
    return ch

def kbhit():
    dr,dw,de = select([sys.stdin], [], [], 0)
    return dr != []     # ここだけ修正

if __name__ == '__main__':
    atexit.register(set_normal_term)
    set_curses_term()

    while 1:
        if kbhit():
            ch = getch()
            break
        sys.stdout.write('.')

    print('done:'+ch)

実際にpython3のプログラムにインポートして使うときは、

from kbhit import *

でインポートして、初期化のときに以下のコードを実行

 atexit.register(set_normal_term)
 set_curses_term()

そしたらあとは、

        if kbhit():
            ch = getch()

で好きなだけkbhit()+getch()できる。やったね。