简体   繁体   中英

Are the key codes of a <Key> event platform-independent?

I wanted to create line numbers for my text editor, but it's a bit complicated: Tkinter adding line number to text widget

So I decided to create a line and column counter, like in the IDLE . To achieve this goal, I decide to listen for the <Key> event generated on a tkinter.Text widget. I did not know which are the properties of an event object , so I decided to take a look in the source code of the Event class (one of the best tutorials :D), and I discovered there are 2 main properties that are interesting for my goal, that is keycode and char .

My question is, are this keycodes platform independents? I would like that my text editor work on all platforms without undefined behaviour, because of wrong interpretation of keycodes .

This is a simple practical functional example of what I would like to do:

from tkinter import *

lines = 1
columns = 0

ARROWS = (8320768, 8124162, 8255233, 8189699)

def on_key_pressed(event=None):
    global columns, lines

    if event.keycode == 3342463: # return
        if columns > 0 and lines > 0:
            columns -= 1
            if columns < 0: # decrease lines if columns < 0
                columns = 0
                lines -= 1
        if columns == 0 and lines > 1:
            lines -= 1

    elif event.keycode == 2359309: # newline
        columns = 0
        lines += 1
    else:
        if event.keycode not in (ARROWS) and event.char != '':
            columns += 1

    print("Lines =", lines)
    print("Columns =", columns, '\n\n')
    print(event.keycode, ' = ', repr(event.char))

root = Tk()

text = Text(root)

text.pack(fill='both', expand=1)
text.bind('<Key>', on_key_pressed)

root.mainloop()

What are the problems of this approach (after answering my first question)?

On my Logitech keyboard with win7, the arrow keycodes are 37, 38, 39, and 40, with repr '', and return is 13, with repr '\\r'. These keycode do not match either what you show, or the claims of this page .

However, the same page suggests using event.keysym or event.keysym_num. What it does not point out is that the nums for non-unicode-character keys, like Shift, Up, F1, etc, are just below 2**16 (65536), in the 'private use area'. The number for ascii chars are their ascii codes, which equal their unicode ordinals. I suspect that the number for all BMP unicode chars is their unicode ordinal (tk only encodes the BMP).

The only use I can see for keycodes is to tell the difference between number keypad keys and the same key elsewhere.

The problems with your approach is that it will be almost impossible to compute the information you seek. All the information you need is available by querying widget attributes and/or data so there's really no point in trying to keep track of the line and column yourself.

This example is not an elegant solution, so I think it is better to "hardcode" keycodes depending on the operating system.

# 1. Generate keystrokes using Python + Tkinter.
# 2. Save needed keycodes in the dictionary.
# 3. Use dictionary with keycodes to handle keystrokes independently from
#    operating system, language or (maybe?) keyboard model.
# This is not an elegant solution, so I think it is better to "hardcode"
# keycodes depending on the operating system.
import tkinter as tk

def keystroke(event):
    dict[event.keycode] = event.keysym  # save keycodes into the dictionary

def keyboardevent(str):
    # Code that simulated 'key' being pressed on keyboard
    temp.after(10, lambda: temp.event_generate('<Key-{}>'.format(str)))

temp = tk.Tk()
temp.withdraw()  # remove the window from the screen (without destroying it)
temp.bind('<Key>', keystroke)
dict = {}  # dictionary of the needed keycodes
keyboardevent('w')  # generate needed keyboard events
keyboardevent('s')
keyboardevent('a')
keyboardevent('d')
temp.after(20, temp.destroy)  # this is not needed anymore
temp.mainloop()

# Start your code here
def keys_handler(event):
    if event.keycode in dict:
        print(dict[event.keycode])

root = tk.Tk()
root.focus_force()
root.bind('<Key>', keys_handler)
root.mainloop()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM