programing

키 스트로크로 잠시 루프를 죽이는 방법?

lovejava 2023. 9. 11. 21:19

키 스트로크로 잠시 루프를 죽이는 방법?

저는 시리얼 데이터를 읽고 while loop을 사용하여 csv 파일에 쓰고 있습니다.사용자가 충분한 데이터를 수집했다고 생각하면 while loop을 죽일 수 있기를 바랍니다.

while True:
    #do a bunch of serial stuff

    #if the user presses the 'esc' or 'return' key:
        break

opencv를 사용하여 이와 같은 작업을 수행했지만 이 애플리케이션에서 작동하지 않는 것 같습니다(그리고 어쨌든 이 기능만을 위해 opencv를 가져오고 싶지 않습니다).

        # Listen for ESC or ENTER key
        c = cv.WaitKey(7) % 0x100
        if c == 27 or c == 10:
            break

그래서. 어떻게 하면 사용자가 루프에서 벗어나도록 할 수 있을까요?

또한 while 루프가 종료된 후에도 스크립트가 계속 실행되어야 하기 때문에 키보드 인터럽트를 사용하고 싶지 않습니다.

가장 쉬운 방법은 그냥 일상적인 것으로 방해하는 것입니다.Ctrl-CSIGINT) (SIGINT)

try:
    while True:
        do_something()
except KeyboardInterrupt:
    pass

Ctrl-CKeyboardInterrupt키워야 할 거야, 그냥 고리 밖에서 잡고 그냥 무시해요.

비표준 모듈이 필요 없고 100% 운반이 가능한 솔루션이 있습니다.

import _thread

def input_thread(a_list):
    raw_input()             # use input() in Python3
    a_list.append(True)
    
def do_stuff():
    a_list = []
    _thread.start_new_thread(input_thread, (a_list,))
    while not a_list:
        stuff()

다음 코드가 저에게 적합합니다.openCV(import cv2)가 필요합니다.

이 코드는 계속해서 눌러진 키를 찾는 무한 루프로 구성되어 있습니다.이 경우 'q' 키를 누르면 프로그램이 종료됩니다.다른 키(이 예에서는 'b' 또는 'k')를 눌러 변수 값을 변경하거나 기능을 실행하는 등의 다양한 작업을 수행할 수 있습니다.

import cv2

while True:
    k = cv2.waitKey(1) & 0xFF
    # press 'q' to exit
    if k == ord('q'):
        break
    elif k == ord('b'):
        # change a variable / do something ...
    elif k == ord('k'):
        # change a variable / do something ...

Python 3.7의 경우 user297171의 아주 멋진 답변을 복사하고 변경하여 테스트한 Python 3.7의 모든 시나리오에서 작동합니다.

import threading as th

keep_going = True
def key_capture_thread():
    global keep_going
    input()
    keep_going = False

def do_stuff():
    th.Thread(target=key_capture_thread, args=(), name='key_capture_thread', daemon=True).start()
    while keep_going:
        print('still going...')

do_stuff()
pip install keyboard

import keyboard

while True:
    # do something
    if keyboard.is_pressed("q"):
        print("q pressed, ending loop")
        break

여기 저에게 효과가 있었던 해결책이 있습니다.여기저기 게시물에서 아이디어를 얻었습니다.정의된 키(abortKey)를 누를 때까지 루프가 종료되지 않습니다.루프는 가능한 한 빨리 중지되고 다음 반복으로 실행하려고 하지 않습니다.

from pynput import keyboard
from threading import Thread
from time import sleep

def on_press(key, abortKey='esc'):    
    try:
        k = key.char  # single-char keys
    except:
        k = key.name  # other keys    

    print('pressed %s' % (k))
    if k == abortKey:
        print('end loop ...')
        return False  # stop listener

def loop_fun():
    while True:
        print('sleeping')
        sleep(5)
        
if __name__ == '__main__':
    abortKey = 't'
    listener = keyboard.Listener(on_press=on_press, abortKey=abortKey)
    listener.start()  # start to listen on a separate thread

    # start thread with loop
    Thread(target=loop_fun, args=(), name='loop_fun', daemon=True).start()

    listener.join() # wait for abortKey

파이훅이 도움이 될 겁니다http://sourceforge.net/apps/mediawiki/pyhook/index.php?title=PyHook_Tutorial#tocpyHook%5FTutorial4

키보드 후크 참조. 키보드만 사용하는 것이 아니라 특정 키보드 상호 작용을 원하는 경우 보다 일반화됩니다.방해하다.

또한 일반적으로 (사용 용도에 따라) Ctrl-C 옵션을 사용하여 스크립트를 삭제하는 것이 타당하다고 생각합니다.

이전 질문도 참조:python에서 어떤 키를 눌렀는지 탐지

ㅇㅇ가 .sys.exit().

파이썬의 핵심 라이브러리에 있는 시스템 라이브러리에는 프로토타입 제작 시 매우 편리한 exit 기능이 있습니다.코드는 다음과 같습니다.

import sys

while True:
    selection = raw_input("U: Create User\nQ: Quit")
    if selection is "Q" or selection is "q":
        print("Quitting")
        sys.exit()
    if selection is "U" or selection is "u":
        print("User")
        #do_something()

나는 rayzinnz의 답을 특정 키로 스크립트를 끝내도록 수정했습니다, 이 경우 탈출 키.

import threading as th
import time
import keyboard

keep_going = True
def key_capture_thread():
    global keep_going
    a = keyboard.read_key()
    if a== "esc":
        keep_going = False


def do_stuff():
    th.Thread(target=key_capture_thread, args=(), name='key_capture_thread', daemon=True).start()
    i=0
    while keep_going:
        print('still going...')
        time.sleep(1)
        i=i+1
        print (i)
    print ("Schleife beendet")


do_stuff()

라이브러리에서 입니다. 와 에서 입니다 은 입니다 에서 와

됩니다.
입력한 합니다.

2 및 3Python 2.7및 3합니다.

import thread
import sys

def getch():
    import termios
    import sys, tty
    def _getch():
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(fd)
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch
    return _getch()

def input_thread(char):
    char.append(getch())

def do_stuff():
    char = []
    thread.start_new_thread(input_thread, (char,))
    i = 0
    while not char :
        i += 1

    print "i = " + str(i) + " char : " + str(char[0])

do_stuff()

이 스레드를 따라 토끼구멍을 내려가면서 저는 이것에 도달했고, Win10과 Ubuntu 20.04에서 작동합니다.저는 단순히 스크립트를 죽이는 것 이상의 것을 원했고, 특정 키를 사용하기를 원했고, MS와 리눅스 둘 다에서 작동해야 했습니다.

import _thread
import time
import sys
import os

class _Getch:
    """Gets a single character from standard input.  Does not echo to the screen."""
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            self.impl = _GetchUnix()

    def __call__(self): return self.impl()

class _GetchUnix:
    def __init__(self):
        import tty, sys

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch

class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        msvcrt_char = msvcrt.getch()
        return msvcrt_char.decode("utf-8")

def input_thread(key_press_list):
    char = 'x'
    while char != 'q': #dont keep doing this after trying to quit, or 'stty sane' wont work
        time.sleep(0.05)
        getch = _Getch()
        char = getch.impl()
        pprint("getch: "+ str(char))
        key_press_list.append(char)

def quitScript():
    pprint("QUITTING...")
    time.sleep(0.2) #wait for the thread to die
    os.system('stty sane')
    sys.exit()

def pprint(string_to_print): #terminal is in raw mode so we need to append \r\n
    print(string_to_print, end="\r\n")

def main():
    key_press_list = []
    _thread.start_new_thread(input_thread, (key_press_list,))
    while True:
        #do your things here
        pprint("tick")
        time.sleep(0.5)

        if key_press_list == ['q']:
            key_press_list.clear()
            quitScript()

        elif key_press_list == ['j']:
            key_press_list.clear()
            pprint("knock knock..")

        elif key_press_list:
            key_press_list.clear()

main()

로 인정된 답변.KeyboardInterrupt저는 신뢰할 수 없었지만, pyinput으로 다음과 같은 솔루션이 가능했습니다(Python 3.10, Linux).While-loop은 다음과 같이 종료됩니다.q를 누릅니다

from pynput.keyboard import Listener  # pip install pynput

keyboard_quit = False

def keyboard_handler(key):
    global keyboard_quit
    if hasattr(key, 'char') and key.char == 'q':
        keyboard_quit = True

keyboard_listener = Listener(on_press=keyboard_handler)
keyboard_listener.start()  # Non-blocking

while not keyboard_quit:
    # Do something

이것은 --pip install pynput을 사용한 설치 pynput에 도움이 될 수 있습니다.

from pynput.keyboard import Key, Listener
def on_release(key):
    if key == Key.esc:
        # Stop listener
        return False

# Collect events until released
while True:
    with Listener(
            on_release=on_release) as listener:
        listener.join()
    break 

여기에 현재 반복을 안전하게 종료한 후 종료하는 간단한 Windows 솔루션이 있습니다.'Esc' 키로 루프를 깨고 종료하는 카운터 예제와 함께 사용했습니다.msvcrt 패키지의 kbhit()getch() 기능을 사용합니다.타임 패키지는 이벤트 간에 시간 지연을 설정하기 위한 완화 이유로만 호출됩니다.

import msvcrt, time

print("Press 'Esc' to stop the loop...")
x = 0
while True:
    x += 1
    time.sleep(0.5)
    print(x)
    
    if msvcrt.kbhit():
        if msvcrt.getch() == b'\x1b':
            print("You have pressed Esc! See you!")
            time.sleep(2)    
            break

kbhit() 함수는 키 누르기가 읽기 대기 중인 경우 True를 반환합니다.

getch() 함수는 키 누름을 읽고 결과 문자를 바이트 문자열로 반환합니다.어떤 키와 함께 사용해도 좋습니다.

b'\x1b'는 'Esc' 키의 바이트 문자열 문자입니다.

다음은 잡을 필요 없이 을 사용하는 또 다른 예입니다.SIGINT(Ctrl+c).

답변 했듯이 @Atcold 의 에서 처럼 한 를 된 를 처럼 Ctrl+c루프에서 장시간 실행 작업을 중단하고 정의되지 않은 상태로 둘 수 있습니다.호출 중인 라이브러리에서 장시간 실행되는 작업이 발생하면 특히 짜증이 날 수 있습니다.

는 에서 는 가 를 가 를 에서 q요를 누릅니다.Enter바로 하려면 . 를 하려면 과 이 합니다 합니다 이 를 과 하려면 ._Getch() 대답에서

import time
from threading import Thread, Event


def read_input(q_entered_event):
    c = input()
    if c == "q":
        print("User entered q")
        q_entered_event.set()


def do_long_running_stuff():
    q_pressed_event = Event()
    input_thread = Thread(target=read_input,
                          daemon=True,
                          args=(q_pressed_event,))
    input_thread.start()
    while True:
        print("I am working ...")
        time.sleep(1)
        if q_pressed_event.is_set():
            break
    
    print("Process stopped by user.")


if __name__  == "__main__":
    do_long_running_stuff()
from time import sleep
from threading import Thread
import threading

stop_flag = 0
    
    def Wait_Char():
        global stop_flag
        v = input("Enter Char")
        if(v == "z"):
            stop_flag = 1
    
    
    def h():
        while(True):
            print("Hello Feto")
            time.sleep(1)
            if(stop_flag == 1):
                break
    
    
    thread1 = Thread(target=Wait_Char)
    thread2 = Thread(target=h)
    thread1.start()
    thread2.start()
    print("threads finished...exiting")

이것은 최선의 방법은 아니지만 당신이 원하는 을 할 수 있습니다.
Running 2 Threads 한 개는 사용자가 루프를 중지할 키를 기다리고 있습니다.
방식Wait_Char 방식)
는 루프용개로개p한d
방법HΩ)
그리고 둘 다 정지 과정을 제어하는 전역 변수 stop_flag를 봅니다. z를 누르면 정지합니다.

from pynput import keyboard

def on_press(key):
    if key == keyboard.Key.esc:
        return False

i = 0
with keyboard.Listener(on_press=on_press) as listener:
    # Your infinite loop
    while listener.running:
        print(i)
        i=i+1
print("Done")

효과가 있습니다...

import keyboard

while True:
    print('please say yes')
    if keyboard.is_pressed('y'):
         break
print('i got u :) ')
print('i was trying to write you are a idiot ')
print('  :( ')

entry는 'ENTER'를 사용합니다.

언급URL : https://stackoverflow.com/questions/13180941/how-to-kill-a-while-loop-with-a-keystroke