Bruce Simonson
Bruce Simonson

Reputation: 173

python tkinter - detecting arrow keys when shift and function key are pressed, or control and function key are pressed

This is a follow-on question to an earlier question ( python tkinter - detecting arrow keys when an alternate key is pressed )

I would also like to be able to detect if the function key is pressed, along with the shift, or the control key, while one of the arrow keys (up, down, left, and right) is pressed.

import tkinter

def on_key_press(event):

    if event.state & 0x0001: # shift key
        if event.keysym == 'Down':
            print("shift and down arrow")
        elif event.keysym == 'Up':
            print("shift and up arrow")
        elif event.keysym == 'Left':
            print("shift and left arrow")
        elif event.keysym == 'Right':
            print("shift and right arrow")
 
    elif event.state & 0x????:     # shift key and function key 0x????
        if event.keysym == 'Down':
            print("shift and function and down arrow")
        elif event.keysym == 'Up':
            print("shift and function  and up arrow")
        elif event.keysym == 'Left':
            print("shift and function and left arrow")
        elif event.keysym == 'Right':
            print("shift and function and right arrow")
 
    elif event.state & 0x0004: # control key
        if event.keysym == 'Down':
            print("control and down arrow")
        elif event.keysym == 'Up':    
            print("control and up arrow")
        elif event.keysym == 'Left':
            print("control and left arrow")
        elif event.keysym == 'Right':
            print("control and right arrow")

    elif event.state & 0x????:    # control key and function key 0x????
        if event.keysym == 'Down':
            print("control and function and down arrow")
        elif event.keysym == 'Up':
            print("control and function and up arrow")
        elif event.keysym == 'Left':
            print("control and function and left arrow")
        elif event.keysym == 'Right':
            print("control and function and right arrow")

    elif event.state & 0x20000: # alternate key
        if event.keysym == 'Down':
            print("alternate and down arrow")
        elif event.keysym == 'Up':
            print("alternate and up arrow")
        elif event.keysym == 'Left':
            print("alternate and left arrow")
        elif event.keysym == 'Right':
            print("alternate and right arrow")

I'm hoping there's a pair of 0x???? masks that will make this easy.


UPDATE, following the excellent comment by Derek below.

As it happens, my Lenovo laptop has a "Fn" key on the left side of the keyboard, but this key does not work like the shift, control, or alternate keys.

Specifically, this Fn key does not generate keystrokes like "ctrl-q" or "shift-A" (for example) ... that is (for example) there is no detected key event for "Fn-q" or "Fn-A" on this keyboard.

Upvotes: 0

Views: 78

Answers (1)

Derek
Derek

Reputation: 2244

These are the event.state values from a text.bind(Key, function)

Caps lock off

  1. 262144 = 0 = "1000000000000000000" - open
  2. 262145 = 1 = "1000000000000000001" - shift
  3. 262148 = 4 = "1000000000000000100" - ctrl
  4. 262149 = 5 = "1000000000000000101" - shift+ctrl

Caps lock on

  1. 262146 = 2 = "1000000000000000010" - open
  2. 262147 = 3 = "1000000000000000011" - shift
  3. 262150 = 6 = "1000000000000000110" - ctrl
  4. 262151 = 7 = "1000000000000000111" - ctrl+shift

The following code demonstrates event behaviour and event.state values.

The equivalent binary values enable the use of bit-wise testing.

This code simply groups event.state values into tuples for testing and displays the results.

from tkinter import Tk, LabelFrame, Text

master = Tk()
frame = LabelFrame(master, text = "Report")
frame.grid(sticky = "nsew")
text = Text(frame, undo = 1)
text.grid(sticky = "nsew")

def react(event):
    if event.state in (5, 7, 262149, 262151):
        k = f"ctrl+shift keys {event.state}"
    elif event.state in (4, 6, 262148, 262150):
        k = f"ctrl key {event.state}"
    elif event.state in (1, 3, 262145, 262147):
        k = f"shift key {event.state}"
    elif event.state in (0, 2, 262144, 262146):
        k = f"open key {event.state}"
    else:
        k = f"?? {event.keysym} & {event.state} ??"
    result = f"{k} = {event.keysym}"
    frame['text'] = result
    print(result)

text.bind("<Key>", react)

text.focus_set()
master.mainloop()

Upvotes: 1

Related Questions