skyzzle
skyzzle

Reputation: 187

Python: how would I write a keyevent?

So simply put I want my code to call a event like OnKeyPress("Keyname") or something, each time I press a key. I don't want to use tkinter.

I have a Update method that gets called 20 times a second that's in a parent class I have several child classes that have that function called. On some of them I want to use a key press event to make parts of my robot I am working on move.(eg: while I am pressing the up arrow the robot will move foreword) tkinter is well not designed for this its more for drawing content on a screen and I want to make my code more efficient for its purpous. also I would prefer to have my own then use a pre-made one so I can get a better understanding on how it works.

Upvotes: 0

Views: 1208

Answers (2)

Terry Jan Reedy
Terry Jan Reedy

Reputation: 19144

I urge you to reconsider not using tkinter. Ignoring the GUI stuff, it has a tested, cross-platform, asynchonous event loop system that handles both scheduled (timed) events and key press and release events. And it is written in C and updated as platforms change. (See the comments for the recipe @Ty quoted about platform changes.) You will find it very difficult to reproduce the same facilities in Python.

Usage would start with

import tkinter
root = tkinter.Tk()
root.withdraw()  # make the window invisible

Thereafter, one can ignore the GUI stuff and only use root.bind(key event, function) and root.after(milleseconds, function, *args). (In the meanwhile, the option to use graphics to interact with the robot, in the future, would still be there.)

Given existing move_forward and stop_move functions, here is how to make a robot move while pressing up-arrow.

root.bind('<KeyPress-Up>', move_forward)
root.bind('<keyRelease-Up>' stop_move)

About the importance of being asynchronous (non-blocking): I presume you call an update function 20 times a second by calling time.sleep(.05) between each update. This is a blocking call and during this period your code is frozen. It cannot do anything and cannot respond to events.

Suppose you develop two or more animations for the robot: say one for the arms, one for the head (or whatever is appropriate for your robot). Each would consist of a series times commands, implemented by root.after calls. Now suppose you want to run two or more animations in parallel. Assuming that each only requires a small fraction of CPU time, this would be trivial with tkinter because each would run asynchronously and not block the program from doing other things. With a blocking event system, you would have to write a new animation each each combination you want.

Upvotes: 1

Ty Staszak
Ty Staszak

Reputation: 115

This should work

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
        return msvcrt.getch()
class _Getch:
    def init(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            self.impl = _GetchUnix()

def __call__(self): return self.impl() getch = _Getch() while True: if getch.impl(): print getch.impl()

Every thing up to the while loop you need. Then when ever you call getch.impl() it will wait for a input, but if there is none, it will move on. That's why I used the while loop

DISCLAIMER
This is not my code, please check out:
http://code.activestate.com/recipes/134892/

Upvotes: 0

Related Questions