Check for keypress on Linux xterm ?

H

hlubenow

Hello,

I'd like to check, if a single key is pressed on a Linux xterm.
This code waits for a key to be pressed and returns the character:

--------------------------------------------

#!/usr/bin/env python

import sys
import tty
import termios

fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)

def getOneKey():

try:
tty.setcbreak(sys.stdin.fileno())
ch = sys.stdin.read(1)
return ord(ch)

finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)

while True:
a = chr(getOneKey())
print a

--------------------------------------------

My problem is, I don't want my program to wait for the keypress.
I just want to check, if a key is currently pressed and if not, I'd like to
continue with my program (like "INKEY$" in some BASIC-dialects).

I tried several things:

- event-handling from pygame: But that would open a pygame-window, I don't
need.
- same thing for window-managers like Tkinter.
- threads: I couldn't do it (especially return values from thread-functions
to the main-program).
- curses: "nodelay()" or "halfdelay()" sound interesting. Maybe; but don't
know how right now. I even wouldn't be able to "print" then ...
- python-Xlib: Too complicated for me too right now; perhaps, if
documentation becomes more complete.

Does anybody know a code example (for Linux xterm) that does it ?

TIA

H.
 
G

Grant Edwards

My problem is, I don't want my program to wait for the keypress.
I just want to check, if a key is currently pressed and if not, I'd like to
continue with my program (like "INKEY$" in some BASIC-dialects).

The answer to this frequently asked question is actually in the FAQ:

http://www.python.org/doc/faq/library.html#how-do-i-get-a-single-keypress-at-a-time

Google finds us further examples:

http://mail.python.org/pipermail/pythonmac-sig/2004-February/010140.html
http://mail.python.org/pipermail/python-list/2000-June/041251.html
 
H

hlubenow

Grant said:

You're answer is only less than half correct:

Most of the given examples use something like

c = sys.stdin.read(1)

like my example does. This blocks input. At the end of your last link the
author there says it. He also shows some ways into my direction.
I'll test them.

H.
 
G

Grant Edwards

http://www.python.org/doc/faq/library.html#how-do-i-get-a-single-keypress-at-a-time

You're answer is only less than half correct:

Most of the given examples use something like

c = sys.stdin.read(1)

like my example does. This blocks input.

read() will not block if the file has been set to non-blocking
mode. That's what these two lines in the FAQ answer do:

oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)

I do make mistakes, but before telling somebody he's wrong, it
might be a good idea to actually try what he's suggested. ;)
 
H

hlubenow

Grant said:
I do make mistakes, but before telling somebody he's wrong, it
might be a good idea to actually try what he's suggested. ;)

I completely agree. The script waited at first for key-input, so I thought,
I was right. But I was not. I apologize !

H.
 
H

hlubenow

I said:
Hello,

I'd like to check, if a single key is pressed on a Linux xterm.
My problem is, I don't want my program to wait for the keypress.
I just want to check, if a key is currently pressed and if not, I'd like
to continue with my program (like "INKEY$" in some BASIC-dialects).

Ok, here's the code I use now. Thanks to Grant Edwards for pointing me into
the right direction:

----------------------------------------------------------

#!/usr/bin/env python

import os
import sys
import tty
import termios
import fcntl
import time

fd = sys.stdin.fileno()

oldterm = termios.tcgetattr(fd)
oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)

tty.setcbreak(sys.stdin.fileno())
newattr = termios.tcgetattr(fd)
newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO


def oldTerminalSettings():
termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)


def newTerminalSettings():
termios.tcsetattr(fd, termios.TCSANOW, newattr)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)


def checkKey():

try:
c = sys.stdin.read(1)
return ord(c)

except IOError:
return 0

print
print "Ok, in 3 seconds, I'll check 100 times, which key you press."
print

# Initializing: Things like "raw_input()" won't work after that:
newTerminalSettings()

time.sleep(3)

for i in range(100):
a = "Key pressed: "

key = checkKey()

if key:
a += chr(key)
a += "."
else:
a += "Nothing pressed."

print a

# Somehow it doesn't work, if this loop runs too fast, so:
time.sleep(0.05)

oldTerminalSettings()

print
print "Terminal-settings restored."
print
raw_input("raw_input() works again. So please press Return: ")
print
 
G

Grant Edwards

I said:
Hello,

I'd like to check, if a single key is pressed on a Linux xterm.
My problem is, I don't want my program to wait for the keypress.
I just want to check, if a key is currently pressed and if not, I'd like
to continue with my program (like "INKEY$" in some BASIC-dialects).

Ok, here's the code I use now. Thanks to Grant Edwards for pointing me into
the right direction:

----------------------------------------------------------

#!/usr/bin/env python

import os
import sys
import tty
import termios
import fcntl
import time

fd = sys.stdin.fileno()

oldterm = termios.tcgetattr(fd)
oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)

tty.setcbreak(sys.stdin.fileno())
newattr = termios.tcgetattr(fd)
newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO


def oldTerminalSettings():
termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)


def newTerminalSettings():
termios.tcsetattr(fd, termios.TCSANOW, newattr)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)


def checkKey():

try:
c = sys.stdin.read(1)
return ord(c)

except IOError:
return 0

Ah, but how do you tell "no key" from ctrl-@ (which has a
ordinal value of 0)? If I were you, I'd return None in the case
where there is nothing to return:

def checkKey():
try:
return ord(sys.stdin.read(1))
except IOError:
return None

I'm also not sure if there are other possible causes for the
IOError exception that you'd need to watch out for. Ideally,
you'd check to make sure its an EAGAIN.
print
print "Ok, in 3 seconds, I'll check 100 times, which key you press."
print

# Initializing: Things like "raw_input()" won't work after that:
newTerminalSettings()

time.sleep(3)

for i in range(100):
a = "Key pressed: "

key = checkKey()

if key:

And here, you'd have this:

if key is not None:
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top