How to detect ESCape keypress in Python?
Asked Answered
E

6

14

I am running a process in a command window (Windows 7, Python 3.1) where I would like the user to abort the process by pressing Esc key. However, pressing Esc doesn't appear to do anything, the loop never breaks. I have also tried running the script from within my IDE (Wing), but again, the loop cannot be interrupted.

The following is a stripped-down version of my proof-of-concept test...

import msvcrt
import time

aborted = False

for time_remaining in range(10,0,-1):
    # First of all, check if ESCape was pressed
    if msvcrt.kbhit() and msvcrt.getch()==chr(27):
        aborted = True
        break

    print(str(time_remaining))       # so I can see loop is working
    time.sleep(1)                    # delay for 1 second
#endfor timing loop

if aborted:
    print("Program was aborted")
else:
    print("Program was not aborted")

time.sleep(5)  # to see result in command window before it disappears!

If anyone could tell me where I might be going wrong I would be most grateful.

Elbe answered 28/2, 2011 at 0:56 Comment(0)
C
8

Python 3 strings are unicode and, therefore, must be encoded to bytes for comparison. Try this test:

if msvcrt.kbhit() and msvcrt.getch() == chr(27).encode():
    aborted = True
    break

Or this test:

if msvcrt.kbhit() and msvcrt.getch().decode() == chr(27):
    aborted = True
    break

Or this test:

if msvcrt.kbhit() and ord(msvcrt.getch()) == 27:
    aborted = True
    break
Chladek answered 28/2, 2011 at 3:12 Comment(0)
B
6

You should really strip down more, like this one below:

>>> import msvcrt
>>> ch = msvcrt.getch()
# Press esc
>>> ch
b'\x1b'
>>> chr(27)
'\x1b'
>>> ch == chr(27)
False

So here is the problem: msvcrt.getch() returns bytes, chr(27) returns string. In Python 3 they are two distinct types, so the "==" part will never work, and the if statement will always be evaluated as False.

The solution should be obvious to you.

More about strings vs bytes, from the book Dive into Python 3.

The interactive console is very useful for debugging, try use it more :)

Baten answered 28/2, 2011 at 5:24 Comment(0)
K
6

You don't need encode, decode, chr, ord, ....

if msvcrt.kbhit() and msvcrt.getch() == b'\x1b':

or if you'd like to see "27" in the code somewhere:

if msvcrt.kbhit() and msvcrt.getch()[0] == 27:
Kleinstein answered 28/2, 2011 at 5:41 Comment(1)
Being brought-up on ASCII values, I prefer the 2nd example. Thanks.Elbe
M
5

Python 2/3 compatible code:

import time, sys

ESC = '\x1b'
PY3K = sys.version_info >= (3,)
if PY3K:
    from msvcrt import kbhit, getwch as _getch
else:
    from msvcrt import kbhit, getch as _getch
while not kbhit() or _getch() != ESC:
    print(time.asctime())
    time.sleep(1)

Code parts are taken from pager module with more stuff inside.

Meteorite answered 19/12, 2012 at 10:10 Comment(0)
H
1

Have you tried using a different key to test if it's not just that key?

Did you also try the examples here to see if they worked?

Haase answered 28/2, 2011 at 1:43 Comment(1)
Hi Corey, tried the examples suggested and started getting "b'\x1b'" output, which thanks to other posters here I now know is the bytestring version, which has to be converted to unicode. Regards.Elbe
A
-2

import cv2 as cv

a = cv.waitkey(0)

if (a == 27 or ord('esc') == 27): aborted = True break

Arthrospore answered 14/12, 2023 at 22:40 Comment(1)
ord('esc') is not valid. you can only use single characters not a string!Horsewhip

© 2022 - 2024 — McMap. All rights reserved.