Python cross-platform listening for keypresses?
Asked Answered
A

4

21

I need to listen for certain keypresses in a python terminal program without pausing execution with raw_input. I've seen people use a few windows specific ways of listening for keystrokes and I've seen people use large modules like tkinter and pygame which I want to avoid.

Is there a lightweight module out there that does this cross platform (at least ubuntu, windows, mac)? or is there a way to use just the event system from tkinter, pygame, etc...?

If not, how should I approach tackling this? My first thought is to redirect stdin to another process and keep checking to see if it contains one of my event keys.


edit

Thank you @unutbu for taking the time to mark this question that is 3 years old and successfully answered as a duplicate of another question whose answers do not apply to this question because I specifically asked about a non-blocking solution.

Astronomical answered 18/2, 2011 at 16:48 Comment(0)
K
8

I don't know of any cross-platform lightweight module that listens for keypresses. But here's a suggestion in case you want to implement something simple:

Check out this question on getting a single keypress at a time in the Python FAQ. You could experiment a bit with blocking reads from sys.stdin and threading. But this may only work on Unix. On Windows, you can use msvcrt.kbhit.

Combining the keypress recipe from the Python FAQ and the msvcrt module, the resulting kbhit function would go like this:

try:
    from msvcrt import kbhit
except ImportError:
    import termios, fcntl, sys, os
    def kbhit():
        fd = sys.stdin.fileno()
        oldterm = termios.tcgetattr(fd)
        newattr = termios.tcgetattr(fd)
        newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
        termios.tcsetattr(fd, termios.TCSANOW, newattr)
        oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
        fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
        try:
            while True:
                try:
                    c = sys.stdin.read(1)
                    return True
                except IOError:
                    return False
        finally:
            termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
            fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
Karlykarlyn answered 18/2, 2011 at 22:0 Comment(5)
def kbhit(): ... return sys.stdin.read(1)Divorcee
+1 I was able to accomplish what I needed in this case based off of your answer. thanks.Astronomical
-1 This does not contain something equivalent to the msvcrt module's kbhit() function which only tests if a key has been pressed or not. This is because it's based on code from the Python FAQ for getting single keypresses one at a time. Your adaption does that when one is available and then throws the character read away, so it is lost.Antilogism
What do you once you've imported kbhit? How do you use it?Ashaashamed
EI capitan 10.11.3 (15D21), I got this error: termios.error: (25, 'Inappropriate ioctl for device')Blackpoll
C
6

Short answer: no Keypresses are system-dependent. They are interrupt-driven. They one of the basic things built into most modern OSes. They have different philosophies that can't be unified in a generic way without losing functionality.

you might try- termios = unix, posix-style file-descriptor driven

curses = portal terminal-style handling (which is a specific console-based paradigm not generic)

Python wraps certain classes of input that might come from the keyboard: e.g., sys.stdin for console inupt.

But trying to get universal keyboard input is a very general problem that's inherently platform-dependent.

Castra answered 18/2, 2011 at 22:8 Comment(0)
N
0

you can use python module plataform, to get the current OS and then make a solution for each platform:

import platform
platform.platform()
'Linux-3.3.0-8.fc16.x86_64-x86_64-with-fedora-16-Verne'
Nastassia answered 6/12, 2021 at 11:31 Comment(0)
A
-1

Here's how you can do it on Windows:

"""

    Display series of numbers in infinite loop
    Listen to key "s" to stop
    Only works on Windows because listening to keys
    is platform dependent

"""

# msvcrt is a windows specific native module
import msvcrt
import time

# asks whether a key has been acquired
def kbfunc():
    #this is boolean for whether the keyboard has bene hit
    x = msvcrt.kbhit()
    if x:
        #getch acquires the character encoded in binary ASCII
        ret = msvcrt.getch()
    else:
        ret = False
    return ret

#begin the counter
number = 1

#infinite loop
while True:

    #acquire the keyboard hit if exists
    x = kbfunc() 

    #if we got a keyboard hit
    if x != False and x.decode() == 's':
        #we got the key!
        #because x is a binary, we need to decode to string
        #use the decode() which is part of the binary object
        #by default, decodes via utf8
        #concatenation auto adds a space in between
        print ("STOPPING, KEY:", x.decode())
        #break loop
        break
    else:
        #prints the number
        print (number)
        #increment, there's no ++ in python
        number += 1
        #wait half a second
        time.sleep(0.5)
Ashaashamed answered 16/4, 2014 at 3:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.