Skip to content
Advertisement

Cannot bind NumPad minus key on Linux with Tkinter

I encountered an issue regarding KeyPress binds in tkinter when switching between Windows and Linux while using a NumPad. Using self.bind("-", function) works on Windows, however is not triggered on Linux.

With the following code snippet I found out that the events of a keyboard-minus differs from a numpad-minus.

Code:

import tkinter as tk


class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.bind("<Key>", self.action)
        self.count = 0

    def action(self, e):
        print(e)
        self.count += 1


app = App()
app.mainloop() 

Output:

NumPad:
<KeyPress event state=Mod2 keysym=KP_Subtract keycode=82 char=‘-‘ x=323 y=-184

KeyBoard:
<KeyPress event state=Mod2 Keysym=minus keycode=61 char=’-‘ x=376 y=-27 

Is there a way to make Linux recognize the “-” char in a tkinter bind whether it is from keyboard or NumPad?

Advertisement

Answer

Is there a way to make Linux recognize the “-” char from both the keyboard and the NumPad in a tkinter bind?

I have wrote code where you can choose from the OptionMenu from the options you have:

You could bind both keysyms to the same function. – jasonharper

keep binding to any key and dispatch based on the char attribute of the event. – Sven Marnach

use both the upper methods.

Running the provided code you can see that binding to both, ‘any key’ and the ‘minus’ key suppresses the key event for pressing ‘any key’ to be triggered in case the ‘minus’ key is pressed:

# https://stackoverflow.com/questions/63464407/cannot-bind-numpad-minus-key-on-linux-with-tkinter
import tkinter as tk

enable = None
# enable = 'binding and action'
# enable = 'binding only'
# enable = 'only action'

class App(tk.Tk):
    def __init__(self):
        global enable
        from tkinter import StringVar, OptionMenu
        tk.Tk.__init__(self)
        choices = ['binding and action', 'binding only', 'only action']
        self.sv = StringVar()
        
        if enable == None:
            print("DEFAULT CHOICE: enable == 'binding and action'")
            enable = 'binding and action'

        if enable == 'binding and action': 
            self.bind("<KP_Subtract>", self.on_minus_bind)
            self.bind("<minus>"      , self.on_minus_bind)
            self.bind("<Key>",         self.action)
            self.sv.set('binding and action')

        if enable == 'binding only': 
            self.bind("<KP_Subtract>", self.on_minus_bind)
            self.bind("<minus>"      , self.on_minus_bind)
            self.sv.set('binding only')

        if enable == 'only action': 
            self.bind("<Key>",         self.action)
            self.sv.set('only action')
            
        self.om = OptionMenu(None, self.sv, *choices, command=self.on_option_change)
        self.om.pack()
        
        self.count = 0

    def on_option_change(self, e):
        enable = self.sv.get()
            
        if enable == 'binding and action': 
            self.bind("<KP_Subtract>", self.on_minus_bind)
            self.bind("<minus>"      , self.on_minus_bind)
            self.bind("<Key>",         self.action)

        if enable == 'binding only': 
            self.unbind("<Key>")
            self.bind("<KP_Subtract>", self.on_minus_bind)
            self.bind("<minus>"      , self.on_minus_bind)

        if enable == 'only action': 
            self.unbind("<KP_Subtract>")
            self.unbind("<minus>")
            self.bind("<Key>",         self.action)

    def action(self, e):
        if e.char == '-':
            self.on_minus_action(e)
        else: 
            print('action call: ', e, type(e))
        self.count += 1
    
    def on_minus_bind(self, e):
        print('bind-event :  "minus" pressed', e, type(e))

    def on_minus_action(self, e): 
        print('action-call:  "minus" pressed', e, type(e) )

app = App()
app.mainloop() 
User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement