Skip to main content

global-shortcut-portal

A pure-Python library for the Wayland Global Shortcut Portal (org.freedesktop.portal.GlobalShortcuts).
Lets any application register and receive global keyboard shortcuts on Wayland, without X11 key grabbing.

AI was used heavily during development, with human review and testing of all code.
This is a personal library I wanted and I'm sharing it in case it's useful to others.

Requirements

  • Python >= 3.10
  • dbus-next (pure Python, no C extensions)
  • A Wayland compositor with a Global Shortcuts portal backend (KDE Plasma 6+, GNOME 48+, Hyprland, etc.)

Installation

pip install global-shortcut-portal

On systems with an externally managed environment (e.g. recent Debian/Ubuntu, Fedora, Arch Linux with system Python) use pip install --user or a virtual environment. Alternatively, install with uv:

uv pip install global-shortcut-portal

For development, clone the repo and pull group dev:

git clone https://codeberg.org/marvin1099/python-global-shortcut-portal # if not done jet
cd python-global-shortcut-portal # if not done jet
uv sync --group dev

Reference Example

The repository includes a fully-commented reference app at examples/reference_example_app.py that demonstrates the complete session lifecycle with interactive controls:

Key Action
b Bind example shortcuts with default triggers
a Grow the list: bind a third shortcut (resets session)
f Force empty: two reset+bind rounds that remove shortcuts
e Register shortcuts without triggers
l List bound shortcuts
c Open the native config dialog
r Reset the session (needed before re-binding)
q Quit
python examples/reference_example_app.py

Flatpak

xdg-desktop-portal was built for sandboxed apps, so this library runs unchanged inside a Flatpak sandbox, portal access is granted by default, no D-Bus permissions needed (see docs/flatpak.md). The only difference is the app ID: the portal attributes shortcuts to the sandbox app ID ($FLATPAK_ID). The library ships small detection helpers (is_flatpak(), flatpak_id(), portal_app_id(), session_type()) for apps that need to know.

A ready-to-build Flatpak for the reference example lives in flatpak/:

flatpak-builder --force-clean --user --install flatpak/build \
  flatpak/page.codeberg.marvin1099.GlobalShortcutPortalExample.json
flatpak run page.codeberg.marvin1099.GlobalShortcutPortalExample

The app ID page.codeberg.marvin1099.GlobalShortcutPortalExample only exists
in this repo for testing, there is no such entry on Flathub.
After testing, uninstall it with:

flatpak remove page.codeberg.marvin1099.GlobalShortcutPortalExample

Documentation

Quick Start

import asyncio
from global_shortcut_portal import (
    GlobalShortcutsSession,
    Portal,
    Shortcut,
    SessionCallback,
)


class MyCallback(SessionCallback):
    def on_activated(self, event):
        print(f"Shortcut activated: {event.shortcut_id}")

    def on_deactivated(self, event):
        print(f"Shortcut deactivated: {event.shortcut_id}")


async def main():
    portal = Portal()
    await portal.connect()

    session = GlobalShortcutsSession(
        portal,
        app_id="org.example.MyApp",
        callback=MyCallback(),
    )
    await session.connect()

    shortcuts = [
        Shortcut(
            id="toggle-overlay",
            description="Toggle overlay window",
            preferred_trigger="CTRL+ALT+SPACE",
        ),
    ]
    bound = await session.bind(shortcuts)
    for s in bound:
        print(f"Bound: {s.id} -> {s.trigger_description}")

    await asyncio.Event().wait()


asyncio.run(main())

Features

  • Async API via dbus-next (pure Python asyncio D-Bus library)
  • Session life-cycle management (create, bind, list, configure, close)
  • Supports Registry.Register for xdg-desktop-portal >= 1.20
  • Full signal handling (Activated, Deactivated, ShortcutsChanged)
  • Shortcut trigger parsing and formatting (XDG shortcuts specification)
  • Version 2 portal features (ConfigureShortcuts)

Notes

  • BindShortcuts is only allowed once per session.
    There is no portal method to unbind or update a bound shortcut.
    Use the native config dialog or create a new session to change the set.
  • Changing the set on a new session works.
    Binding a reduced set on a new session replaces the old one,
    so shortcuts missing from the new set are removed
    (action f uses this to clear everything).
    DEs usualy persist triggers per app_id,
    so a re-bound shortcut with the same ID keeps its stored trigger.
    To change one, first bind a set without it,
    then reset again and rebind the full set with the new trigger.

Metadata

Release files for global-shortcut-portal 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for global-shortcut-portal 0.2.1
File Size Uploaded
global_shortcut_portal-0.2.1.tar.gz 28.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for global-shortcut-portal 0.2.1
File Interpreter ABI Platform
global_shortcut_portal-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 53.0 kB

Release files / global_shortcut_portal-0.2.1.tar.gz

Download URL global_shortcut_portal-0.2.1.tar.gz
Size 28.4 kB
Tags Source
SHA-256 checksum
How to use checksums
0f8477b93c31cdba33fc37a1106ee61b1821caf1890f6b0d2e0745759980c4ff
BLAKE2b-256 checksum
How to use checksums
f43e373987c5e2f0a891777540f9b28a0c9aa4aaa7b97686ea639d70239277a2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / global_shortcut_portal-0.2.1-py3-none-any.whl

Download URL global_shortcut_portal-0.2.1-py3-none-any.whl
Size 24.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a697747fee2acd40c2bff32d49096804980e01eb1143305145d1a955669450ba
BLAKE2b-256 checksum
How to use checksums
c6da0dad9b520156385ae358d733db7fce778a5a6e6d3460fab31d17973abad7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page