Search code examples
pythonpython-3.xtkinterpynputglobal-hotkey

Global hotkey in Tkinter


I want to add global hotkey (using the pynput module) to my Tkinter script (Random Number Generator). I want to get random number every time I press 'f7' button. It also has to work without focusing on the app. Unfortunately the app is not responding after a while. It worked once/twice but after a minute or so it got frozen.

import tkinter as tk
import random
from pynput import keyboard

rng = random.SystemRandom()

def Draw():
    global text

    frame=tk.Frame(root,width=100,height=100,relief='solid',bd=0)
    frame.place(relx = 0.5, rely = 0.5, anchor = 'center')
    text=tk.Label(frame,text='HELLO', font = "Helvetica 65 bold", justify='center')
    text.pack()


def on_press(key):
    try:
        k = key.char
    except:
        k = key.name

    if k in ['f7']:
        return False #stop listening


n = 0
def Refresher():
    global text
    global n

    text.configure(text=rng.randint(0,100), fg ="white", bg = "black")
    root.after(100, Refresher)

    if n == 1:
        listener = keyboard.Listener(on_press=on_press)
        listener.start()
        listener.join()

    n = 1

root=tk.Tk()
root["bg"] = "black"
root.title("RNG")
Draw()
Refresher()
root.mainloop()

Solution

  • I found the solution. We need bindglobal library and then we have global hotkeys in Tkinter. More info: https://libraries.io/pypi/bindglobal

    My code:

    import tkinter as tk
    import random
    from bindglobal import BindGlobal
    
    rng = random.SystemRandom()
    
    def Draw():
        global text
    
        frame=tk.Frame(root,width=100,height=100,relief='solid',bd=0)
        frame.place(relx = 0.5, rely = 0.5, anchor = 'center')
        text=tk.Label(frame,text='HELLO', font = "Helvetica 65 bold", justify='center')
        text.configure(text=rng.randint(0,100), fg ="white", bg = "black")
        text.pack()
    
    
    def Refresher(e):
        global text
        text.configure(text=rng.randint(0,100), fg ="white", bg = "black")
    
    
    root = tk.Tk()
    
    root.title("RNG - F7")
    root["bg"] = "black"
    
    Draw()
    
    bg = BindGlobal()
    bg.start()
    bg.gbind("<f7>",Refresher)
    
    root.mainloop()
    

    Plus I needed to modify the mentioned library because there was no support for 'F7' button.

    Find and open bindglobal/init.py and add 'f7', e.g. like this:

    class TkKeys(object):
        tk_keys = {}
        for i in ( 'space','BackSpace', 'Tab'
            , 'Delete', 'End', 'Home', 'Caps_Lock'
            ,'Left','Right', 'Up', 'Down', 'f7'
            ,'Menu','Insert', 'Pause', 'Num_Lock', 'Scroll_Lock' #Those fails on OSX
            ):