IT Share you

파이썬에서 키보드 폴링 (키 누르기 감지)

shareyou 2020. 12. 4. 21:26
반응형

파이썬에서 키보드 폴링 (키 누르기 감지)


콘솔 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에서 이것을 수행하는 올바른 파이썬 방법은 무엇입니까? 또한 필수는 아니지만 Linux 로의 이식성은 나쁘지 않습니다.


표준 접근 방식은 선택 모듈 을 사용하는 것 입니다.

그러나 이것은 Windows에서는 작동하지 않습니다. 이를 위해 msvcrt 모듈의 키보드 폴링을 사용할 수 있습니다 .

종종이 작업은 여러 스레드 ( "감시"되는 장치 당 하나씩)와 장치에 의해 중단되어야하는 백그라운드 프로세스로 수행됩니다.



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

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 __name__ == '__main__':
    curses.wrapper(main)

좋아요, 댓글에 내 솔루션을 게시하려는 시도가 실패했기 때문에 여기에 제가 말하려는 내용이 있습니다. 다음 코드를 사용하여 네이티브 Python에서 원하는 것을 정확하게 수행 할 수 있습니다 (다른 곳은 아니지만 Windows에서).

import msvcrt 

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

이 답변 중 어느 것도 나를 위해 잘 작동하지 않았습니다. 이 패키지 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()

파이 게임 이 아이디어를 훔치기 위해 이것을 어떻게 처리 하는지 볼 수 있습니다 .


댓글에서 :

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;
}

그리고 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)

나는 키 누름을 확인하기 위해 이것을 사용하고 있으며 훨씬 더 간단해질 수 없습니다.

#!/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)

While curses is not working on windows, there is a 'unicurses' version, supposedly working on Linux, Windows, Mac but I could not get this to work


I've come across a cross-platform implementation of kbhit at http://home.wlu.edu/~levys/software/kbhit.py (made edits to remove irrelevant code):

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 != []

Make sure to read() the waiting character(s) -- the function will keep returning True until you do!


If you combine time.sleep, threading.Thread, and sys.stdin.read you can easily wait for a specified amount of time for input and then continue, also this should be cross-platform compatible.

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

You could also place this into a function like so

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

Although this will not return anything so instead you should use the multiprocessing pool module you can find that here: how to get the return value from a thread in python?

참고URL : https://stackoverflow.com/questions/292095/polling-the-keyboard-detect-a-keypress-in-python

반응형