web-dev-qa-db-ja.com

pythonでキーボードをポーリング(キー押下を検出)

コンソールpythonアプリからキーボードをポーリングするにはどうすればよいですか?具体的には、他の多くのI/Oアクティビティ(ソケットの選択、シリアルポートアクセスなど)の中で、これに似た何かをしたいと思います。

   while 1:
      # doing amazing Pythonic embedded stuff
      # ...

      # periodically do a non-blocking check to see if
      # we are being told to do something else
      x = keyboard.read(1000, timeout = 0)

      if len(x):
          # ok, some key got pressed
          # do something

Windowsでこれを行う正しいPythonicの方法は何ですか?また、必須ではありませんが、Linuxへの移植性は悪くありません。

60
K. Brafford

標準的なアプローチは、 select モジュールを使用することです。

ただし、これはWindowsでは機能しません。そのためには、 msvcrt モジュールのキーボードポーリングを使用できます。

多くの場合、これは複数のスレッドで行われます。「監視」されているデバイスごとに1つと、デバイスによって中断される必要のあるバックグラウンドプロセスです。

31
S.Lott

import sys
import select

def heardEnter():
    i,o,e = select.select([sys.stdin],[],[],0.0001)
    for s in i:
        if s == sys.stdin:
            input = sys.stdin.readline()
            return True
    return False
16
Stefan

Cursesモジュールを使用したソリューション。押された各キーに対応する数値の印刷:

import curses

def main(stdscr):
    # do not wait for input when calling getch
    stdscr.nodelay(1)
    while True:
        # get keyboard input, returns -1 if none available
        c = stdscr.getch()
        if c != -1:
            # print numeric value
            stdscr.addstr(str(c) + ' ')
            stdscr.refresh()
            # return curser to start position
            stdscr.move(0, 0)

if __== '__main__':
    curses.wrapper(main)
16
W. Russell

解決策をコメントに投稿する試みが失敗したため、ここに私が言おうとしていたことを示します。次のコードを使用して、ネイティブPython(Windowsではなく、他の場所ではない))から望みどおりにできます。

import msvcrt 

def kbfunc(): 
   x = msvcrt.kbhit()
   if x: 
      ret = ord(msvcrt.getch()) 
   else: 
      ret = 0 
   return ret
15
K. Brafford

これらの答えはどれも私にはうまくいきませんでした。このパッケージpynputは、まさに必要なことを行います。

https://pypi.python.org/pypi/pynput

from pynput.keyboard import Key, Listener

def on_press(key):
    print('{0} pressed'.format(
        key))

def on_release(key):
    print('{0} release'.format(
        key))
    if key == Key.esc:
        # Stop listener
        return False

# Collect events until released
with Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()
12
wroscoe

pygame がどのようにこれを処理していくつかのアイデアを盗むかを見るかもしれません。

5
Rizwan Kassim

コメントから:

import msvcrt # built-in module

def kbfunc():
    return ord(msvcrt.getch()) if msvcrt.kbhit() else 0

助けてくれてありがとう。 PyKeyboardAccess.dllと呼ばれるC DLL)を記述し、crt conio関数にアクセスして、このルーチンをエクスポートしました。

#include <conio.h>

int kb_inkey () {
   int rc;
   int key;

   key = _kbhit();

   if (key == 0) {
      rc = 0;
   } else {
      rc = _getch();
   }

   return rc;
}

そして、pythonでctypesモジュールを使用してアクセスします(python 2.5)に組み込まれています):

import ctypes
import time

#
# first, load the DLL
#


try:
    kblib = ctypes.CDLL("PyKeyboardAccess.dll")
except:
    raise ("Error Loading PyKeyboardAccess.dll")


#
# now, find our function
#

try:
    kbfunc = kblib.kb_inkey
except:
    raise ("Could not find the kb_inkey function in the dll!")


#
# Ok, now let's demo the capability
#

while 1:
    x = kbfunc()

    if x != 0:
        print "Got key: %d" % x
    else:
        time.sleep(.01)
5
K. Brafford

キーを押すかどうかを確認するためにこれを使用していますが、これ以上簡単にすることはできません。

#!/usr/bin/python3
# -*- coding: UTF-8 -*-

import curses, time

def main(stdscr):
    """checking for keypress"""
    stdscr.nodelay(True)  # do not wait for input when calling getch
    return stdscr.getch()

while True:
    print("key:", curses.wrapper(main)) # prints: 'key: 97' for 'a' pressed
                                        # '-1' on no presses
    time.sleep(1)

CursesはWindowsで動作していませんが、Linux、Windows、Macで動作していると思われる「unicurses」バージョンがありますが、これを動作させることはできませんでした

1
ullix

http://home.wlu.edu/~levys/software/kbhit.pykbhitのクロスプラットフォーム実装に遭遇しました(無関係なコードを削除するために編集を行いました) ):

_import os
if os.name == 'nt':
    import msvcrt
else:
    import sys, select

def kbhit():
    ''' Returns True if a keypress is waiting to be read in stdin, False otherwise.
    '''
    if os.name == 'nt':
        return msvcrt.kbhit()
    else:
        dr,dw,de = select.select([sys.stdin], [], [], 0)
        return dr != []
_

read()待機中の文字を確認してください-関数は、あなたがするまでTrueを返し続けます!

1
ivan_pozdeev

Time.sleep、threading.Thread、sys.stdin.readを組み合わせると、入力のために指定された時間を簡単に待ってから続行できます。これもクロスプラットフォームで互換性があります。

t = threading.Thread(target=sys.stdin.read(1) args=(1,))
t.start()
time.sleep(5)
t.join()

これを次のような関数に配置することもできます

def timed_getch(self, bytes=1, timeout=1):
    t = threading.Thread(target=sys.stdin.read, args=(bytes,))
    t.start()
    time.sleep(timeout)
    t.join()
    del t

これは何も返しませんが、代わりにマルチプロセッシングプールモジュールを使用する必要があります: pythonのスレッドから戻り値を取得する方法?

0
ChrisBrownie55