crackalamoo
crackalamoo

Reputation: 13

Python Tkinter on a Mac: Why can't I detect when a key is held down?

I am trying to make a simple Tkinter program in Python that prints "True" while I hold down the "U" key and "False" when I let go. Unfortunately, when I run the program it prints "True" when I press "U" and then 300 milliseconds later prints "False".

I want this to remain in Tkinter or another built-in module, I don't want to use external modules like Pygame. I am on a mac, OS X El Capitan, python 2.7.10. I am open to using another programming language as long as it is run from and sends keypress information to this python file. This is my code:

import Tkinter
root = Tkinter.Tk()

U = False
Udone = True

def Ustart():
    global Udone
    Udone = True
def Press(event):
    global U
    global Udone
    U = True
    Udone = False
    print("True")
    root.after(300, Ustart)
def Release(event):
    global U
    global Udone
    if Udone:
        U = False
        print("False")


root.bind("u", Press)
root.bind("<KeyRelease-u>", Release)
root.mainloop()

Upvotes: 1

Views: 1349

Answers (2)

hexagon
hexagon

Reputation: 101

Sorry I'm so late to answer this, but I still think it's important. After searching for years I've only now discovered the answer. There are a few things to know first (though this isn't the complete list because you're using Python 2):

  • This is not a bug with Tkinter (the Python wrapper for Tcl/Tk) but with Tk itself
  • This bug has actually been fixed in 2018 in a later version of Tk 8.6
  • However, Python 2 will only dynamically link with a Tk version 8.5 or below
  • The Mac OS X built-in Tk 8.5.9 doesn't include this bug (unlike all other distributions of Tk 8.5 that I've seen) but does include other fatal errors, so don't use it

The solution is to download and build the source release of the last release of Tk 8.5 (https://github.com/tcltk/tk/releases/tag/core-8-5-19), but modify the file tkMacOSXKeyEvent.c in the same manner as the developers of Tk to fix the glitch (the commit is here: https://github.com/tcltk/tk/commit/797282fc2929c8427bd830748d7b08ea022c1177).

Upvotes: 1

user4171906
user4171906

Reputation:

This also works, at least on my Linux system. Note that the print loop is separate from the set_the_variable functions.

import Tkinter
import os

os.system('xset r off')

class KeyRepeat():
    def __init__(self, root):
        root.bind("u", self.press)
        root.bind("<KeyRelease-u>", self.release)
        self.check_key=True
        Tkinter.Button(root, text="Exit", command=root.quit, bg="orange").grid()

    def press(self, event=None):
        self.check_key=True
        self.print_result()

    def print_result(self):
        if self.check_key:
            print("True")
            root.after(300, self.print_result)

    def release(self, event):
        self.check_key=False
        print("False")

root = Tkinter.Tk()
K=KeyRepeat(root)
root.mainloop()

os.system('xset r on')

Upvotes: 0

Related Questions