Python: handling key up and key down events (may be a keyboard limitation)

I want to detect key “chording”, ie I want to know which keys are pressed together. Potentially the user could be pressing 10 keys (one for each finger ;o)).

A submitter elsewhere explained the basics of binding key up and key down events, which has enabled me to make good progress. This code is as canonical as I can get:

from tkinter import *
from tkinter import ttk

class MainUI:
    def __init__(self, root):

        mainframe = Frame(root)
        mainframe.grid(column=0, row=0, sticky=(N, W, E, S))

        self.key_text = StringVar()
        self.key_entry = ttk.Entry(mainframe, width=16, justify=CENTER, textvariable=self.key_text)
        self.key_entry.insert(0,"Click here")
        self.key_entry.grid(column=1, row=1) #, sticky=(W)
        self.key_entry.bind('<KeyPress>', self.keyPressHandler)
        self.key_entry.bind('<KeyRelease>', self.keyReleaseHandler)
        self.keysPressed = [] # List of which keys are currently pressed
        for child in mainframe.winfo_children(): 
            child.grid_configure(padx=5, pady=5)

    def keyPressHandler(self, event):       
        if event.char in self.keysPressed: return # Ignore key repeats: we only want the first keydown event
        else:
            self.keysPressed.append(event.char)
            print("Key down:", event.char)
        
    def keyReleaseHandler(self, event):
        self.keysPressed.remove(event.char)
        print("Key up:", event.char)

root = Tk()
ui = MainUI(root)
root.mainloop()

This almost works:

  • It will pick up any two keys pressed simultaneously (eg ‘g’ and ‘h’)
  • It will pick up multiple keys if the keys are at the left or right end of the keyboard (eg ‘q’, ‘w’, ‘e’, ‘r’)
  • But it won’t pick up multiple keys from the middle of the keyboard (eg ‘g’, ‘h’, ‘j’)

The behaviour with an external USB keyboard and the laptop’s built in keyboard is similar, though I don’t think identical.

My guess is that I’m hitting some limitation of keyboard scanning, and that the problem is nothing to do with Python.

Thoughts?

Leave a Comment