Entry
Tk: Binding to the pressing of modifier keys *by themselves*
Jul 5th, 2000 09:59
Nathan Wallace, unknown unknown, Hans Nowak, Snippet 88, Charles G Waldman
"""
Packages: gui.tkinter
"""
"""
> In Tk, is there a way (even a hack) which would allow one to find out
> whether a given key is pressed (e.g. the Control or Alt key)? I'd like
> to emulate the standard GUI pattern where the cursor is a magnifying
> glass w/ a '+' inside, except when a modifier is pressed, in which case
> a '-' is displayed.
This is a little bit tricky; I have 2 kludgy solutions.
If you bind an event handler to "<Motion>" events you can look at the
event.state to determine if any modifiers are down. The modifier bits are
encoded in the low byte of "state", the high byte indicates mouse buttons.
The drawback with this is that if you press a modifier key, the cursor is
not changed immediately, but only when the mouse is moved. Kind of ugly.
If you have focus set to the window, and bind handlers to "<KeyPress>" and
"<KeyRelease>" events you will get notified when a modifier is pressed
alone, as long as you have the input focus. However, if you recieve a
KeyPress event that, say, the Shift_L key is going down, the event.state
field does not yet include the information that the Shift modifier is
applied. If you hold down Control while you press Shift, the event that
the Shift key is going down includes the modifier bit for Control, but not
yet the modifier bit for Shift. Similarly, when the keys are released,
the event.state includes the modifier bits for the modifier which is being
released. So you can't use event.state in these handlers, instead you
have to keep track of the modifiers yourself. This is doable; below is an
example, which isn't 100% correct (you can fool it by holding down some
combinations of modifiers) but it generally does what you are looking for;
you could probably make it work cleanly with a little bit of effort.
It would be really nice if there were a way to query the current
state of the modifier keys, I can't see a way to do this. Maybe
someone who is more of a Tk guru will have some better suggestions.
"""
#!/usr/local/bin/python
from Tkinter import *
root = Tk()
frame = Frame(root)
canvas = Canvas(frame)
canvas.pack()
frame.pack()
def main_cursor():
frame['cursor']='circle'
def alt_cursor():
frame['cursor']='box_spiral'
modifiers = ("Shift_L",
"Shift_R",
"Alt_L",
"Alt_R",
"Control_L",
"Control_R"
)
def press(ev):
if ev.keysym not in modifiers:
return
alt_cursor()
def release(ev):
if ev.state == 0 or ev.keysym in modifiers:
main_cursor()
frame.bind("<KeyPress>",press)
frame.bind("<KeyRelease>",release)
frame.focus()
main_cursor()
root.mainloop()