Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for keyboard shortcuts in menu #75

Open
suurjaak opened this issue Dec 12, 2020 · 1 comment
Open

Support for keyboard shortcuts in menu #75

suurjaak opened this issue Dec 12, 2020 · 1 comment

Comments

@suurjaak
Copy link

First of all, thank you for this library, a very handy cross-platform solution to a very common need.

What do you think about adding support for keyboard shortcuts, i.e. underlined characters in menu item texts? Currently, pystray passes the menu texts straight to the underlying backend, so that specifying "E&xit" produces a nice underlined x-shortcut on Windows, but on Linux the text is displayed exactly as given. On Linux, the standard shortcut character has been underscore, e.g. using "E_xit" (except for the brave new Gnome Shell which does not support shortcut accelerators at all).

So, perhaps pystray.Menu could have an additional method set_accelerator(char), where char would specify the symbol the invoker has used in their menu texts? Then the library would replace the character in menu texts with the backend-specific accelerator symbol - or strip it altogether if the backend does not support shortcuts. And in texts where the user wants this symbol to actually be displayed, they should give it in double, e.g. "Save && e&xit" would produce "Save & exit" with x underlined as the shortcut.

It would make sense for a cross-platform library to encapsulate such platform-specific logic.

@MaxBQb
Copy link

MaxBQb commented Aug 20, 2022

In other menus keyboard selection has underscore indication:
6523 image_thumb_668BD4CB

Sadly, system tray menu doesn't.
As workaround, you may use unicode underscore symbols as example:

def insert_underscore(text: str, at: int):
    """
    Make chosen letter underscored

    :param text: String to modify
    :param at: Position of letter to underscore
    :return: String with unicode underscore inserted
    """
    underscore = "\u0332"
    insert_pos = at + 1  # this underscore symbol applies to previous symbol
    return f'{text[:insert_pos]}{underscore}{text[insert_pos:]}'

As for me, I'd like to use automatic '&' + underscore insertion, at least for now:

def make_tray_shortcut(text: str, shortcut_symbol='&', look_for='&'):
    """
    Search for letter right after `look_for` subsequence or uses first letter instead.
    Underscore this letter and mark it as shortcut for system tray,
    so you may press this letter on keyboard to select corresponding menu item

    :param text: Menu item title
    :param shortcut_symbol: Letter used to mark keyboard shortcut,                   
                            platform-specific char (Windows: & | Linux: _)
    :param look_for: Symbol before letter, chosen as keyboard shortcut
    :return: Menu item title with char-markers
    """
    try:
        shortcut_pos = text.index(look_for) + 1
        text = text.replace(look_for, shortcut_symbol, 1)
    except ValueError:
        text = shortcut_symbol + text
        shortcut_pos = 1
    text = insert_underscore(text, shortcut_pos)
    return text

Usage example:

from pystray import Menu, MenuItem
from example import make_tray_shortcut as ref, some_escape_function as escape


menu = Menu(
	MenuItem(ref("Show console"), ...),
	MenuItem(ref("Run a&t system startup"), ...),
	MenuItem(ref("Mode"), ...),
	Menu.SEPARATOR,
	MenuItem(ref('Open'), Menu(
		MenuItem(ref('Work directory'), ...),
		MenuItem(ref('Settings file'), ...),
	)),
	MenuItem(ref('Re&load from disk'), Menu(...)),
	MenuItem(ref('Check for &updates'), ...),
	Menu.SEPARATOR,
	MenuItem(ref(escape('Save & *Exit'), look_for='*')),  # Escape & with && for Windows
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants