Czy istnieje sposób na odczytanie jednego znaku z danych wprowadzonych przez użytkownika? Na przykład naciskają jeden klawisz na terminalu i jest on zwracany (podobnie jak getch()
). Wiem, że jest w tym funkcja w systemie Windows, ale chciałbym coś, co jest wieloplatformowe.
260
msvcrt.getch
zmsvcrt.getwch
, jak sugeruje tam.Odpowiedzi:
Oto link do strony, która mówi, jak odczytać pojedynczy znak w systemie Windows, Linux i OSX: http://code.activestate.com/recipes/134892/
źródło
ImportError
używany jest wyjątek, jak jakiś rodzaj instrukcji if; dlaczego nie wywołać platformy.system (), aby sprawdzić system operacyjny?w zasadzie odczyta 1 bajt ze STDIN.
Jeśli musisz użyć metody, która nie czeka na
\n
, możesz użyć tego kodu, jak sugerowano w poprzedniej odpowiedzi:( pochodzi z http://code.activestate.com/recipes/134892/ )
źródło
Przepis przepisu ActiveState cytowany dosłownie w dwóch odpowiedziach jest przeprojektowany. Można to sprowadzić do tego:
źródło
0
.Warto również wypróbować bibliotekę readchar , która częściowo opiera się na recepturze ActiveState wspomnianej w innych odpowiedziach.
Instalacja:
Stosowanie:
Testowane w systemach Windows i Linux za pomocą Python 2.7.
W systemie Windows, tylko klawisze która mapa do liter lub kodów ASCII są obsługiwane ( Backspace, Enter, Esc, Tab, Ctrl+ litera ). Na GNU / Linux (w zależności od dokładnego terminalu, może?) Można również uzyskać Insert, Delete, Pg Up, Pg Dn, Home, Endi klucze ... ale potem, nie ma problemów oddzielające te specjalne klucze od .F nEsc
Zastrzeżenie: Podobnie jak w przypadku większości (wszystkich?) Odpowiedzi w tutaj, klawiszy nawigacyjnych, takich jak Ctrl+ C, Ctrl+ Di Ctrl+ Zsą wychwytywane i wrócił (a
'\x03'
,'\x04'
i'\x1a'
, odpowiednio); twój program może być trudny do przerwania.źródło
Alternatywna metoda:
Z tego postu na blogu .
źródło
| os.O_NONBLOCK
. W przeciwnym razie możesz umieścić go w pętli (dobrym pomysłem jest spanie przez chwilę w pętli, aby nie wirować).while True
wtedy użyćwhile 1
.Ten kod, oparty tutaj , poprawnie podniesie KeyboardInterrupt i EOFError, jeśli naciśniesz Ctrl+ Club Ctrl+ D.
Powinien działać w systemach Windows i Linux. Wersja OS X jest dostępna z oryginalnego źródła.
źródło
(Obecnie) najwyższa odpowiedź (z kodem ActiveState) jest zbyt skomplikowana. Nie widzę powodu, aby używać klas, gdy wystarczy zwykła funkcja. Poniżej znajdują się dwie implementacje, które osiągają to samo, ale z bardziej czytelnym kodem.
Oba te wdrożenia:
Wersja 1: czytelna i prosta
Wersja 2: unikaj powtarzalnego importu i obsługi wyjątków:
[EDYCJA] Straciłem jedną zaletę kodu ActiveState. Jeśli planujesz wielokrotnie odczytywać znaki, kod ten pozwala uniknąć (nieistotnego) kosztu powtórzenia importu Windows i obsługi wyjątku ImportError w systemach uniksopodobnych. Podczas gdy prawdopodobnie powinieneś bardziej martwić się o czytelność kodu niż tę pomijalną optymalizację, oto alternatywa (jest podobna do odpowiedzi Louisa, ale getChar () jest samodzielna), która działa tak samo jak kod ActiveState i jest bardziej czytelna:
Przykładowy kod wykonujący jedną z powyższych wersji getChar ():
źródło
Może to być przypadek użycia menedżera kontekstu. Pomijając limity dla systemu operacyjnego Windows, oto moja sugestia:
źródło
self
się__enter__
i miećread
metodę, która powracasys.stdin.read(1)
, a następnie można odczytać wiele znaków w jednym kontekście.Spróbuj użyć tego: http://home.wlu.edu/~levys/software/kbhit.py To nie jest blokowanie (oznacza, że możesz mieć pętlę while i wykryć naciśnięcie klawisza bez zatrzymywania go) i międzyplatformowe.
Przykład użycia tego:
Lub możesz użyć modułu getch z PyPi . Ale to zablokowałoby pętlę while
źródło
To NIE BLOKUJE, odczytuje klucz i przechowuje go w keypress.key.
w twoim programie
źródło
Odpowiedzi tutaj miały charakter informacyjny, ale chciałem również sposób na asynchroniczne uzyskiwanie naciśnięć klawiszy i uruchamianie naciśnięć klawiszy w oddzielnych zdarzeniach, wszystko w sposób bezpieczny dla wątków i na różnych platformach. PyGame też było dla mnie zbyt rozdęte. Więc zrobiłem następujące (w Pythonie 2.7, ale podejrzewam, że jest łatwo przenośne), które, jak sądzę, podzielę się tutaj na wypadek, gdyby był użyteczny dla kogokolwiek innego. Przechowałem to w pliku o nazwie keyPress.py.
Chodzi o to, że możesz po prostu zadzwonić
keyPress.getKey()
, który przeczyta klawisz z klawiatury, a następnie zwróci go.Jeśli chcesz czegoś więcej, stworzyłem
KeyCapture
obiekt. Możesz go utworzyć za pomocą czegoś takiegokeys = keyPress.KeyCapture()
.Następnie możesz zrobić trzy rzeczy:
addEvent(functionName)
przyjmuje dowolną funkcję, która przyjmuje jeden parametr. Następnie po każdym naciśnięciu klawisza funkcja ta będzie wywoływana za pomocą łańcucha tego klawisza podczas wprowadzania. Są one uruchamiane w osobnym wątku, więc możesz zablokować w nich wszystko, co chcesz, i nie zakłóci to działania KeyCapturer ani nie opóźni innych zdarzeń.get()
zwraca klucz w taki sam sposób blokowania jak poprzednio. Jest on teraz potrzebny tutaj, ponieważ klucze są teraz przechwytywane przezKeyCapture
obiekt, więckeyPress.getKey()
byłoby to sprzeczne z tym zachowaniem i oba z nich pominęłyby niektóre klucze, ponieważ tylko jeden klucz może zostać przechwycony na raz. Powiedz też, że użytkownik naciska „a”, a następnie „b”, dzwoniszget()
, użytkownik naciska „c”. Toget()
połączenie natychmiast zwróci „a”, a następnie, jeśli zadzwonisz ponownie, zwróci „b”, a następnie „c”. Ponowne wywołanie spowoduje zablokowanie do momentu naciśnięcia innego klawisza. Zapewnia to, że nie przegapisz żadnych kluczy, w razie potrzeby blokujących. W ten sposób jest trochę inaczej niżkeyPress.getKey()
wcześniejJeśli chcesz zachować zachowanie
getKey()
wstecz,get(lossy=True)
jest podobneget()
, z tym wyjątkiem, że zwraca tylko klawisze naciśnięte po wywołaniuget()
. Tak więc w powyższym przykładzieget()
blokuje się, dopóki użytkownik nie naciśnie „c”, a następnie, jeśli wywołasz go ponownie, będzie blokować, dopóki nie zostanie naciśnięty inny klawisz.getAsync()
jest trochę inny. Jest przeznaczony do czegoś, co wymaga dużego przetwarzania, a następnie czasami wraca i sprawdza, które klawisze zostały naciśnięte. W ten sposóbgetAsync()
zwraca listę wszystkich klawiszy naciśniętych od ostatniego połączeniagetAsync()
, w kolejności od najstarszego klawisza do ostatniego klawisza. Nie blokuje również, co oznacza, że jeśli od ostatniego połączenia nie zostanie naciśnięty żaden klawiszgetAsync()
, pusty[]
zostanie zwrócony.Aby zacząć przechwytywanie klawiszy, trzeba zadzwonić
keys.startCapture()
z Twójkeys
obiekt wykonany powyżej.startCapture
jest nieblokujący i po prostu uruchamia jeden wątek, który rejestruje naciśnięcia klawiszy, a drugi wątek do przetwarzania tych naciśnięć klawiszy. Istnieją dwa wątki, które gwarantują, że wątek, który rejestruje naciśnięcia klawiszy, nie omija żadnych klawiszy.Jeśli chcesz zatrzymać przechwytywanie kluczy, możesz zadzwonić,
keys.stopCapture()
a to zatrzyma przechwytywanie kluczy. Ponieważ jednak przechwytywanie klucza jest operacją blokującą, klucze przechwytujące wątek mogą przechwytywać jeszcze jeden klucz po wywołaniustopCapture()
.Aby temu zapobiec, możesz przekazać opcjonalne parametry do
startCapture(functionName, args)
funkcji, która po prostu sprawdza, czy klucz jest równy „c”, a następnie kończy działanie. Ważne jest, aby ta funkcja działała bardzo niewiele, na przykład sen tutaj spowoduje, że stracimy klucze.Jeśli jednak
stopCapture()
zostanie wywołane w tej funkcji, przechwytywanie klawiszy zostanie natychmiast zatrzymane, bez próby przechwycenia, i że wszystkieget()
połączenia zostaną natychmiast zwrócone, z Brak, jeśli żaden klawisz nie został jeszcze naciśnięty.Ponadto, ponieważ
get()
igetAsync()
przechowuj wszystkie poprzednie naciśnięte klawisze (dopóki ich nie odzyskasz), możesz zadzwonićclearGetList()
iclearAsyncList()
zapomnieć wcześniej naciśnięte klawisze.Należy zauważyć, że
get()
,getAsync()
i zdarzenia są niezależne, więc jeśli zostanie naciśnięty klawisz: 1. Jeden telefon naget()
który czeka, z stratny na powrócą ten klucz. Inne połączenia oczekujące (jeśli istnieją) będą nadal czekać. 2. Ten klucz zostanie zapisany w kolejce kluczy get, dzięki czemuget()
przy stratnym wyłączeniu zwróci najstarszy klawisz, który nie zostałget()
jeszcze zwrócony . 3. Wszystkie zdarzenia będą uruchamiane z tym kluczem jako ich wejściem 4. Ten klucz zostanie zapisany na liściegetAsync()
kluczy, gdzie lis zostanie zwrócony i ustawiony na pustą listę przy następnym wywołaniugetAsync()
Jeśli to wszystko za dużo, oto przykładowy przypadek użycia:
Działa dla mnie dobrze po prostym teście, który przeprowadziłem, ale chętnie przyjmę opinie innych, jeśli coś mi umknęło.
Też zamieściłem to tutaj .
źródło
Komentarz w jednej z pozostałych odpowiedzi wspomniał o trybie szyfrowania, który jest ważny dla implementacji Uniksa, ponieważ generalnie nie chcesz,
KeyboardError
aby getchar zużywał ^ C ( ) (tak jak wtedy, gdy ustawisz terminal w trybie surowym, tak jak robi to większość innych odpowiedzi).Innym ważnym szczegółem jest to, że jeśli chcesz odczytać jeden znak, a nie jeden bajt , powinieneś odczytać 4 bajty ze strumienia wejściowego, ponieważ jest to maksymalna liczba bajtów, z których pojedynczy znak będzie się składał w UTF-8 (Python 3+ ). Odczyt tylko jednego bajtu spowoduje nieoczekiwane wyniki dla znaków wielobajtowych, takich jak strzałki na klawiaturze.
Oto moja zmieniona implementacja dla Uniksa:
źródło
Wypróbuj to z pygame:
źródło
pygame.error: video system not initialized
Recepta ActiveState zawiera mały błąd w systemach „posix”, który zapobiega
Ctrl-C
zakłóceniom (używam Maca). Jeśli wstawię następujący kod do mojego skryptu:Nigdy nie będę w stanie zakończyć skryptu
Ctrl-C
i muszę zabić terminal, aby uciec.Uważam, że następująca linijka jest przyczyną, a także zbyt brutalna:
Poza tym pakiet
tty
nie jest tak naprawdę potrzebny,termios
wystarczy go obsłużyć.Poniżej znajduje się ulepszony kod, który działa dla mnie (
Ctrl-C
przerwie), z dodatkowągetche
funkcją, która echa znaku podczas pisania:Bibliografia:
źródło
curses
Pakiet w Pythonie można wykorzystać, aby wejść do trybu „surowego” dla wprowadzania znaków z terminala z zaledwie kilku stwierdzeń. Głównym zastosowaniem Curses jest przejęcie ekranu w celu uzyskania wyników, co może nie być tym, czego chcesz. Ten fragment kodu używaprint()
zamiast tego instrukcji, które są użyteczne, ale musisz zdawać sobie sprawę z tego, jak curses zmienia zakończenia linii dołączane do danych wyjściowych.źródło
Jeśli robię coś skomplikowanego, używam przekleństw do czytania kluczy. Ale często potrzebuję prostego skryptu Python 3, który korzysta ze standardowej biblioteki i potrafi czytać klawisze strzałek, więc robię to:
źródło
Moje rozwiązanie dla python3, niezależne od pakietów pip.
źródło
Uważam, że jest to jedno z najbardziej eleganckich rozwiązań.
a następnie użyj go w kodzie:
źródło
Przyjęta odpowiedź nie była dla mnie tak dobra (przytrzymałbym klucz, nic by się nie wydarzyło, a następnie nacisnąłem inny klawisz i zadziałałoby).
Po zapoznaniu się z modułem klątw , wydaje się, że to właściwa droga. I jest teraz dostępny dla Windows za pomocą kursorów Windows (dostępny przez pip), więc możesz programować w sposób agnostyczny na platformie. Oto przykład zainspirowany tym ładnym samouczkiem na YouTube:
Zapisz go z
.py
rozszerzeniem lub uruchomcurses.wrapper(getkey)
w trybie interaktywnym.źródło
Odpowiedzi tutaj: raw_input w pythonie bez naciskania enter
Użyj tego kodu
Odniesienie: https://github.com/unfor19/mg-tools/blob/master/mgtools/get_key_pressed.py
źródło
Jeśli chcesz zarejestrować tylko jeden pojedynczy klawisz, naciśnij nawet jeśli użytkownik naciskał go więcej niż jeden raz lub naciskał klawisz dłużej. Aby uniknąć wielokrotnego naciskania wejść, użyj pętli while i przekaż ją.
źródło
jeśli chcesz tylko przytrzymać ekran, aby zobaczyć wynik na terminalu, po prostu napisz
na końcu kodu i przytrzyma ekran
źródło
Wbudowane raw_input powinno pomóc.
źródło