How to identify TKinter's non-printable KeyPress events

I am building an application in Tkinter using several text widgets, and I am working on undo / redo functions that fire on a KeyPress event. (I do not use the text widget built into the stack, because I have objects without tkinter that can also be undone / redo, and I want to save everything on the same stack)

Before I started, I read the tutorials and documentation (e.g. http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm ) that gave me the impression event.char will be empty or None if the key pressed was " special ", not an alphanumeric / punctuation key.

This is actually not the case. Pressing Backspace on my keyboard (I use a Macbook Air running El Capitan) returns event.char from \ x7f.

By reading more about Tcl / TK, I also found out that the X keysyms list is platform-to-platform incompatible, and this, for example, on my Mac, the Shift keys seem to have keyym code 0. This means that my application interprets non-print characters like Delete, or the Shift key as print characters that messed around with my implementation.

I will handle KeyPress general events without a fingerprint separately, but I am still worried about the unexpected behavior of keyboard events for two reasons: 1) my program is designed for multi-platform and 2) there is a high probability that this program will be used by people using non-American keyboards.

My current solution using this as a reference is to check event.keysym_num to see if it is in the range of key numbers / key codes used by printed characters.

Here is a sample 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 any non-printable keys that will fail anyway?
  • Is there a better way to talk about non-printable key events besides key print events in Tkinter / Python? (I considered using unicodecategory or curses.ascii.isprint (), but this check happens every time the user presses a key so that they seem redundant)
  • Are there any other bugs with KeyPress events, especially the inconsistent behavior between Windows / Mac / Linux that I should be aware of? (note: I already know the problems with whitespace, such as tabs and carriage returns)

I am using Python 3 (installed with Homebrew) on a Mac. Thanks!

+6
source share
1 answer

Question 1 and 2:

I believe your method works, but it seems just easier to use the str.isprintable method, it returns a boolean value indicating whether the argument string is printprint:

 >>> "aéûβß\\".isprintable() #Works with various accents, special characters True >>> "\x16".isprintable() False >>> "\n".isprintable() #Excludes all other characters False 

a method using len(repr(event.char) == 3 might work, but it would, for example, also exclude \, which has a 4-character representation ('\\').

Question 3:

As you said, there is a bunch of gotcha (for example: tab event char is "\ t", return is "\ r" ... I don’t know where / if you can find an exhaustive list of these features the only solution I ever Either did, is to try the most common ones (for example, almost all the keys and the Ctrl + key combination on my keyboard, using, of course, the program:

 chars = dict() def LogKey(event, chars = chars): #dict is mutable global char #get the actual value of char dict[char] = event.char # root = Tk() root.bind("<KeyPress>", LogKey) for character in "abcde...123456...²&é\"'(-è_...)": #and so on char = character root.event_generate("<KeyPress-{}>".format(character)) char = "<Control-{}>".format(character) root.event_generate(char) char = "<Control-Shift-{}>".format(character) ... #Inspect the dictonary chars in the end 

This is probably not the best method, but it should cover most cases, you can also extend it to check for multiple keys (e.g. Control-cv) ...

+3
source

All Articles