I'm making an app in Tkinter using multiple Text widgets, and I'm working on undo/redo functionality, which is triggered by a KeyPress event. (I'm not using the text widget's built-in undo stack because I have non-tkinter objects which can also be undone/redone and I want to keep everything in one stack)
Before I began, I read tutorials and documentation (e.g. http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm) which gave me the impression event.char would be empty or None if the key pressed was a 'special' key rather than an alphanumeric/punctuation key.
This is not actually the case. Pressing Backspace on my keyboard (I'm using a Macbook Air running El Capitan) returns an event.char of \x7f.
Reading more about Tcl/TK, I also learned the list of X keysyms are not consistent from platform to platform, and that e.g. on my Mac, the Shift keys apparently have a keysym code of 0. This means my application interpreted unprintable characters like Delete or the Shift key as printable characters, which is messing with my implementation.
I'll handle the common unprintable-key KeyPress events separately anyway, but I'm still concerned about unexpected keyboard event behaviour for two reasons: 1) my program is intended to be multi-platform, and 2) there is a high chance this program will be used by people using non-US keyboards.
My current solution, using this as a reference, is to check event.keysym_num to see if it is within the range of keysym numbers/keycodes used by printable characters.
Here is example code:
from tkinter import *
from tkinter import ttk
root = Tk()
textbox = Text(root, width=60, height=3)
textbox.grid(sticky=(N, S, E, W))
def KeyboardEvent(event):
if event.keysym_num > 0 and event.keysym_num < 60000:
print('This is a printable key. The character is: %r keysym: %r' % \
(event.char, event.keysym_num))
else:
print('This key is unprintable. The character is: %r keysym: %r' % \
(event.char, event.keysym_num))
textbox.bind('<KeyPress>', KeyboardEvent)
root.mainloop()
My questions:
- Will my current method work, or are there non-printable keys that will still fall through?
- Is there a better way to tell non-printable key events apart from printable key events in Tkinter/Python? (I considered using unicodecategory or curses.ascii.isprint() but this check occurs every time the user presses a key so these seemed like overkill)
- Are there any more gotchas with KeyPress events, particularly inconsistent behaviour between Windows/Mac/Linux, that I should be aware of? (note: I'm already aware of issues with whitespace characters such as tabs and carriage returns)
I'm using Python 3 (installed with Homebrew) on a Mac. Thanks!