Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Keyboard hotkeys
#1
I wanted to assign right sided control key as a hotkey to a function using keyboard.add_hotkey, but unfortunately I am not finding specific code to assign right sided control key. Could anybody please help with this. Thanks in advance
Reply
#2
keyboard.add_hotkey('right ctrl', your_function)
If you can't explain it to a six year old, you don't understand it yourself, Albert Einstein
How to Ask Questions The Smart Way: link and another link
Create MCV example
Debug small programs

Reply
#3
(Apr-26-2023, 12:20 PM)buran Wrote:
keyboard.add_hotkey('right ctrl', your_function)

(Apr-26-2023, 12:20 PM)buran Wrote:
keyboard.add_hotkey('right ctrl', your_function)

(Apr-26-2023, 12:20 PM)buran Wrote:
keyboard.add_hotkey('right ctrl', your_function)

Hi buran, thanks for your immediate response.

Unfortunately the code "keyboard.add.hotkey('right ctrl', <function>) does not work as intended. despite mentioning "right" before ctrl, both left and right control keys trigger the function.

here is my code

from tkinter import *
import keyboard


def show_window():
    myWindow.deiconify()
    txtEdit.focus_set()


def hide_window():
    myWindow.withdraw()


keyboard.add_hotkey("=", show_window, suppress=True)
keyboard.add_hotkey('right ctrl', hide_window)

myWindow = Tk()
myWindow.title("OneKey")

wLength = int(round(myWindow.winfo_screenwidth() / 3))  # window length is one third of the screens
wHeight = int(round(myWindow.winfo_screenheight() / 2))  # window height ht is one half of the screen
cLength = int((myWindow.winfo_screenwidth() / 2) - (wLength / 2))  # window is centered in width
cHeight = int((myWindow.winfo_screenheight() / 2) - (wHeight / 2))  # window is centered in height
myWindow.iconbitmap("myKey.ico")  # Add icon to the window
myWindow.configure(bg="#a31f8f")  # Background color

myWindow.geometry(f'{wLength}x{wHeight}+{cLength}+{cHeight}')  # Apply all the dimensions to the window

# Height and width ratios for text widgets dimensions according to the screen and window size
textWidth = wLength - 40
textHeight = wHeight / 2 - 80


frmRaw = Frame(myWindow, bg="#a31f8f", width=textWidth + 40, height=textHeight * 2 + 80)  # Frate to hold both raw
# text and edit text widgets

# Create label and text widgets for raw texts
frmRaw.pack(padx=10, pady=10)
lblRaw = Label(frmRaw, text="RawText", bg="#a31f8f")
lblRaw.place(x=10, y=10)
txtRaw = Text(frmRaw)
txtRaw.place(x=10, y=35, width=textWidth, height=textHeight)


# Create label and text widgets for the text to be edited
lblEdit = Label(frmRaw, text="EditText", bg="#a31f8f")
lblEdit.place(x=10, y=textHeight + 45)
txtEdit = Text(frmRaw)
txtEdit.place(x=10, y=textHeight + 70, width=textWidth, height=textHeight)

# Create OK button and check buttons  
checkCommand = Checkbutton(myWindow, text="Commands")
checkCommand.place(x=50, y=wHeight - 40)
btnOK = Button(myWindow, width=8, height=1, padx=2, pady=2, text="OK", command=hide_window)
btnOK.place(x=wLength - 90, y=wHeight - 40)
txtEdit.focus_set()

myWindow.mainloop()
could you please cross check it and tell me if there are any other codes in which only the right control triggers the function and not with the left control button.

Thank you
Gribouillis write May-01-2023, 08:52 AM:
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply
#4
On windows 10 running Python 3.11, add_hotkey("ctrl") works exactly the same as add_hotkey("right ctrl"). If you bind"ctrl" to funcA and "right ctrl" to funcB, pressing either key calls both functions.

I wondered if the keys mapped to the same key code or something like that. I wrote a tkinter program to spit out key events.
import tkinter as tk

class Window(tk.Tk):
    def __init__(self):
        super().__init__()
        self.bind("<Key>", print)

Window().mainloop()
Output:
<KeyPress event send_event=True state=Mod1 keysym=Control_L keycode=17 x=835 y=292> <KeyPress event send_event=True state=Mod1|0x40000 keysym=Control_R keycode=17 x=835 y=292>
The keycode is the same, but the state and keysym are different. Unfortunately you cannot map the control key in tkinter, but you could map all keys and make your own hotkey mapper.
class Window(tk.Tk):
    keymap = {}

    def __init__(self):
        super().__init__()
        self.keymap["Control_L"] = self.left_ctrl
        self.keymap["Control_R"] = self.right_ctrl
        self.bind("<Key>", self.hotkeys)

    def hotkeys(self, event):
        if event.keysym in self.keymap:
            self.keymap[event.keysym]()

    def left_ctrl(self):
        print("left ctrl")

    def right_ctrl(self):
        print("right ctrl")

Window().mainloop()
I think that looks pretty clean, but it does you no good. You will never get a Control_R event after you witdraw the window.

I tried the same thing using keyboard. First I wrote a generic binder. hotkeys does not pass the key press event as an argument so I used on_press()
import keyboard

def handler(event):
    print(event.__dict__)

keyboard.on_press(handler)
keyboard.wait()
Output:
{'event_type': 'down', 'scan_code': 29, 'time': 1682957871.5058897, 'device': None, 'is_keypad': False, 'modifiers': None, 'name': 'ctrl'} {'event_type': 'down', 'scan_code': 29, 'time': 1682957872.049906, 'device': None, 'is_keypad': False, 'modifiers': None, 'name': 'right ctrl'}
The scan_code for the left and right control keys is the same. Only the name has been changed. You could do something similar to the homebrew tkinter hotkey. Here I use hook_key so my handler is not called for every key event. Hook sends events for "down" and "up". I decided to use the "up" event so the mapper function is only called once per keypress (key repeat generates multiple key down events).
import keyboard

def handler(event):
    if event.event_type == "up":
        if event.name == "ctrl":
            left_ctrl()
        else:
            right_ctrl()

def left_ctrl():
    print("left ctrl")

def right_ctrl():
    print("right ctrl")


keyboard.hook_key("ctrl", handler)
keyboard.wait()
Output:
left ctrl right ctrl
I would choose different hotkeys, but this does work.
import tkinter as tk
import keyboard

class Window(tk.Tk):
    keymap = {}

    def __init__(self):
        super().__init__()
        self.keymap["ctrl"] = self.withdraw
        self.keymap["right ctrl"] = self.show
        keyboard.hook_key("ctrl", self.hotkeys)

    def hotkeys(self, event):
        if event.event_type == "up" and event.name in self.keymap:
            self.keymap[event.name]()

    def show(self):
        self.deiconify()

Window().mainloop()
Reply
#5
(May-01-2023, 06:46 PM)deanhystad Wrote: On windows 10 running Python 3.11, add_hotkey("ctrl") works exactly the same as add_hotkey("right ctrl"). If you bind"ctrl" to funcA and "right ctrl" to funcB, pressing either key calls both functions.

I wondered if the keys mapped to the same key code or something like that. I wrote a tkinter program to spit out key events.
import tkinter as tk

class Window(tk.Tk):
    def __init__(self):
        super().__init__()
        self.bind("<Key>", print)

Window().mainloop()
Output:
<KeyPress event send_event=True state=Mod1 keysym=Control_L keycode=17 x=835 y=292> <KeyPress event send_event=True state=Mod1|0x40000 keysym=Control_R keycode=17 x=835 y=292>
The keycode is the same, but the state and keysym are different. Unfortunately you cannot map the control key in tkinter, but you could map all keys and make your own hotkey mapper.
class Window(tk.Tk):
    keymap = {}

    def __init__(self):
        super().__init__()
        self.keymap["Control_L"] = self.left_ctrl
        self.keymap["Control_R"] = self.right_ctrl
        self.bind("<Key>", self.hotkeys)

    def hotkeys(self, event):
        if event.keysym in self.keymap:
            self.keymap[event.keysym]()

    def left_ctrl(self):
        print("left ctrl")

    def right_ctrl(self):
        print("right ctrl")

Window().mainloop()
I think that looks pretty clean, but it does you no good. You will never get a Control_R event after you witdraw the window.

I tried the same thing using keyboard. First I wrote a generic binder. hotkeys does not pass the key press event as an argument so I used on_press()
import keyboard

def handler(event):
    print(event.__dict__)

keyboard.on_press(handler)
keyboard.wait()
Output:
{'event_type': 'down', 'scan_code': 29, 'time': 1682957871.5058897, 'device': None, 'is_keypad': False, 'modifiers': None, 'name': 'ctrl'} {'event_type': 'down', 'scan_code': 29, 'time': 1682957872.049906, 'device': None, 'is_keypad': False, 'modifiers': None, 'name': 'right ctrl'}
The scan_code for the left and right control keys is the same. Only the name has been changed. You could do something similar to the homebrew tkinter hotkey. Here I use hook_key so my handler is not called for every key event. Hook sends events for "down" and "up". I decided to use the "up" event so the mapper function is only called once per keypress (key repeat generates multiple key down events).
import keyboard

def handler(event):
    if event.event_type == "up":
        if event.name == "ctrl":
            left_ctrl()
        else:
            right_ctrl()

def left_ctrl():
    print("left ctrl")

def right_ctrl():
    print("right ctrl")


keyboard.hook_key("ctrl", handler)
keyboard.wait()
Output:
left ctrl right ctrl
I would choose different hotkeys, but this does work.
import tkinter as tk
import keyboard

class Window(tk.Tk):
    keymap = {}

    def __init__(self):
        super().__init__()
        self.keymap["ctrl"] = self.withdraw
        self.keymap["right ctrl"] = self.show
        keyboard.hook_key("ctrl", self.hotkeys)

    def hotkeys(self, event):
        if event.event_type == "up" and event.name in self.keymap:
            self.keymap[event.name]()

    def show(self):
        self.deiconify()

Window().mainloop()

I get right ctrl and left ctrl respectively with your tkinter code but when I use it in keyboard.on_press_key or keyboard.add_hotkey both ctrls work the same.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Need help with infinite loop & making hotkeys/shortcuts Graxum 1 1,185 Aug-22-2022, 02:57 AM
Last Post: deanhystad
  hotkeys module Skaperen 2 2,905 Apr-06-2017, 04:48 AM
Last Post: Skaperen

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020