keyweave


Namekeyweave JSON
Version 0.12.0 PyPI version JSON
download
home_pagehttps://github.com/GregRos/keyweave
SummaryFramework for defining global hotkeys.
upload_time2025-08-31 15:39:51
maintainerNone
docs_urlNone
authorGregRos
requires_python<4.0,>=3.13
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # keyweave

Keyweave is a Python package for creating and managing global keyboard hotkeys.

- Designed to be easy to observe and debug.
- Hotkeys are grouped into a Layout, which can be activated as a context manager.
- Handlers are attached to Commands, which have labels and descriptions.
- Hotkeys are typically defined using decorators on functions or methods.

## Overview

Key-related objects:

- `Key`: Represents a single mouse, keyboard, or controller key.
- `KeyState`: Represents a `Key` together with a state: `up` or `down`.
- `Hotkey`: A trigger `KeyState` and an unordered set of `KeyState` modifiers.

Command-related objects:

- `CommandMeta`: Just the metadata of a command. Has a label and a description.
- `Command`: A metadata object together with a handler (a function).

These are combined using:

- `Binding`: A Hotkey and the Command it’s bound to.
- `Layout`: A collection of `Binding` objects that listens to input events and picks which `Binding` to activate for each event, if any.
- `LayoutClass`: An object-oriented way of defining a `Layout`.

### Key

An object that describes a mouse or keyboard key. You can access most keys using the `key` import:

```python
import key from keyweave
a = key.a
```

Other keys can be constructed using the `Key` class:

```ts
import Key from keyweave
a = Key("a")
```

### KeyState

This describes a `Key` and whether it’s up or down. At any given time, a `KeyState` is either True or False.

KeyStates are used to filter input events as well as global input state. You can construct a `KeyState` using the `Key.down` or `Key.up` properties:

```python
import key from keyweave
a_down = key.a.down
a_up = key.a.up
```

In some cases, you can pass a `Key` instead of a `KeyState`. In that case, `down` is assumed by default.

You can create an Up `KeyState` using the `~` operator on the key:

```python
import key from keyweave
a_up = ~key.a
```

### Hotkey

A `Hotkey` is a filter on input events consisting of two parts:

- A **Trigger** `KeyState` that’s used to hook the input event.
- A set of **Modifiers**: `KeyStates` which need to be True for the Hotkey to fire.

If a `Hotkey` is triggered by an input event, the event is normally swallowed. However, none of the modifiers are swallowed. If they have side-effects, those must be handled separately.

Note that modifiers don’t just refer to classic modifier keys like `Ctrl`. Any key can be a modifier, and the package doesn’t treat these keys differently from others.

You can construct a Hotkey using the `&` operator between:

1. A `Key` or `KeyState`.
2. An iterable of `Key` or `KeyState` objects which are used as modifiers.

```python
import key from keyweave

key.a.down & [key.b]
key.a & [key.b, key.c.up, key.shift.down]
```

In most cases, you can pass a `Key` or `KeyState` directly instead of a `Hotkey`. In that case, the key can be assumed to be `down` and the modifier list is assumed to be empty.

If you want to avoid swallowing the input event, you can modify the Hotkey using its `passthrough` method:

```python
import key from keyweave
key.a.down.hotkey().passthrough
```

### Command

A Command consists of:

- `CommandMeta`: A label, description, and an emoji. Metadata.
- A handler, which is a function that handles the command.

### Layout

A Layout is an object containing lots of `Hotkey` objects bound to `Command` objects.

Layouts are what actually listens to input events. When an input event is received, each Binding’s Hotkey is checked to see if it’s applicable.

If multiple `Binding` objects turn out to be applicable to one input event, **only one of them will be invoked.** The binding that’s invoked is determined by the highest _specificity_ - the total number of keys the Hotkey references.

If the specificity is the same, then the last defined hotkey is used.

So for example, let’s say we register the hotkeys `Ctrl + Shift + A` and `Ctrl + A` under the same `Layout`. Then if `Ctrl + Shift + A` is pressed, the event matches both hotkeys. But one has a specificity of 2 while the other one has 3.

Thus only the `Ctrl + Shift + A` binding is actually invoked.

However, if you have separate Layouts with these bindings, then multiple bindings can be invoked.

### Negative modifiers

A trigger for a hotkey can be either a key down or a key up event.

Modifiers can also contain key up or key down **states**. A key up modifier is a negative modifier – it means the key should not be held down.

Normally, if you define a hotkey for `Ctrl + A`, it would be invoked even if the user presses `Alt + Ctrl + A`. If you don’t want this behavior, you can add the negative/up modifier `Ctrl + A + ~Alt`.

A negative modifier also increase specificity, which can sometimes be desirable.

## Usage

Using this package means **defining Layout objects**. This can be done

## Object-oriented

The main objects used Keyweave are:

- Command: This is metadata involving a

Bindings are partially implemented using [keyboard](https://pypi.org/project/keyboard/) but due to technical issues involving mouse input and key state, it sometimes has to use the win32 API.

- Capturing mouse input
- Getting key states

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/GregRos/keyweave",
    "name": "keyweave",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.13",
    "maintainer_email": null,
    "keywords": null,
    "author": "GregRos",
    "author_email": "gregros@gregros.dev",
    "download_url": "https://files.pythonhosted.org/packages/8c/7a/ac8a5fe8916aef65016fbdcdd5967d751fec5a66c071c5ea4dc569ad54e0/keyweave-0.12.0.tar.gz",
    "platform": null,
    "description": "# keyweave\n\nKeyweave is a Python package for creating and managing global keyboard hotkeys.\n\n- Designed to be easy to observe and debug.\n- Hotkeys are grouped into a Layout, which can be activated as a context manager.\n- Handlers are attached to Commands, which have labels and descriptions.\n- Hotkeys are typically defined using decorators on functions or methods.\n\n## Overview\n\nKey-related objects:\n\n- `Key`: Represents a single mouse, keyboard, or controller key.\n- `KeyState`: Represents a `Key` together with a state: `up` or `down`.\n- `Hotkey`: A trigger `KeyState` and an unordered set of `KeyState` modifiers.\n\nCommand-related objects:\n\n- `CommandMeta`: Just the metadata of a command. Has a label and a description.\n- `Command`: A metadata object together with a handler (a function).\n\nThese are combined using:\n\n- `Binding`: A Hotkey and the Command it\u2019s bound to.\n- `Layout`: A collection of `Binding` objects that listens to input events and picks which `Binding` to activate for each event, if any.\n- `LayoutClass`: An object-oriented way of defining a `Layout`.\n\n### Key\n\nAn object that describes a mouse or keyboard key. You can access most keys using the `key` import:\n\n```python\nimport key from keyweave\na = key.a\n```\n\nOther keys can be constructed using the `Key` class:\n\n```ts\nimport Key from keyweave\na = Key(\"a\")\n```\n\n### KeyState\n\nThis describes a `Key` and whether it\u2019s up or down. At any given time, a `KeyState` is either True or False.\n\nKeyStates are used to filter input events as well as global input state. You can construct a `KeyState` using the `Key.down` or `Key.up` properties:\n\n```python\nimport key from keyweave\na_down = key.a.down\na_up = key.a.up\n```\n\nIn some cases, you can pass a `Key` instead of a `KeyState`. In that case, `down` is assumed by default.\n\nYou can create an Up `KeyState` using the `~` operator on the key:\n\n```python\nimport key from keyweave\na_up = ~key.a\n```\n\n### Hotkey\n\nA `Hotkey` is a filter on input events consisting of two parts:\n\n- A **Trigger** `KeyState` that\u2019s used to hook the input event.\n- A set of **Modifiers**: `KeyStates` which need to be True for the Hotkey to fire.\n\nIf a `Hotkey` is triggered by an input event, the event is normally swallowed. However, none of the modifiers are swallowed. If they have side-effects, those must be handled separately.\n\nNote that modifiers don\u2019t just refer to classic modifier keys like `Ctrl`. Any key can be a modifier, and the package doesn\u2019t treat these keys differently from others.\n\nYou can construct a Hotkey using the `&` operator between:\n\n1. A `Key` or `KeyState`.\n2. An iterable of `Key` or `KeyState` objects which are used as modifiers.\n\n```python\nimport key from keyweave\n\nkey.a.down & [key.b]\nkey.a & [key.b, key.c.up, key.shift.down]\n```\n\nIn most cases, you can pass a `Key` or `KeyState` directly instead of a `Hotkey`. In that case, the key can be assumed to be `down` and the modifier list is assumed to be empty.\n\nIf you want to avoid swallowing the input event, you can modify the Hotkey using its `passthrough` method:\n\n```python\nimport key from keyweave\nkey.a.down.hotkey().passthrough\n```\n\n### Command\n\nA Command consists of:\n\n- `CommandMeta`: A label, description, and an emoji. Metadata.\n- A handler, which is a function that handles the command.\n\n### Layout\n\nA Layout is an object containing lots of `Hotkey` objects bound to `Command` objects.\n\nLayouts are what actually listens to input events. When an input event is received, each Binding\u2019s Hotkey is checked to see if it\u2019s applicable.\n\nIf multiple `Binding` objects turn out to be applicable to one input event, **only one of them will be invoked.** The binding that\u2019s invoked is determined by the highest _specificity_ - the total number of keys the Hotkey references.\n\nIf the specificity is the same, then the last defined hotkey is used.\n\nSo for example, let\u2019s say we register the hotkeys `Ctrl + Shift + A` and `Ctrl + A` under the same `Layout`. Then if `Ctrl + Shift + A` is pressed, the event matches both hotkeys. But one has a specificity of 2 while the other one has 3.\n\nThus only the `Ctrl + Shift + A` binding is actually invoked.\n\nHowever, if you have separate Layouts with these bindings, then multiple bindings can be invoked.\n\n### Negative modifiers\n\nA trigger for a hotkey can be either a key down or a key up event.\n\nModifiers can also contain key up or key down **states**. A key up modifier is a negative modifier \u2013 it means the key should not be held down.\n\nNormally, if you define a hotkey for `Ctrl + A`, it would be invoked even if the user presses `Alt + Ctrl + A`. If you don\u2019t want this behavior, you can add the negative/up modifier `Ctrl + A + ~Alt`.\n\nA negative modifier also increase specificity, which can sometimes be desirable.\n\n## Usage\n\nUsing this package means **defining Layout objects**. This can be done\n\n## Object-oriented\n\nThe main objects used Keyweave are:\n\n- Command: This is metadata involving a\n\nBindings are partially implemented using [keyboard](https://pypi.org/project/keyboard/) but due to technical issues involving mouse input and key state, it sometimes has to use the win32 API.\n\n- Capturing mouse input\n- Getting key states\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Framework for defining global hotkeys.",
    "version": "0.12.0",
    "project_urls": {
        "Homepage": "https://github.com/GregRos/keyweave"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "59da03ec347769c30497580f527004ec99e13e92e75ce635b5d501e129d9c41c",
                "md5": "118a719b1b38687a4d1e49561602968e",
                "sha256": "a2275e18fbe4659e9e40b91168f9d4c7ba6e65cb09c5ace80dc70b84e4f27c3b"
            },
            "downloads": -1,
            "filename": "keyweave-0.12.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "118a719b1b38687a4d1e49561602968e",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.13",
            "size": 20878,
            "upload_time": "2025-08-31T15:39:50",
            "upload_time_iso_8601": "2025-08-31T15:39:50.113603Z",
            "url": "https://files.pythonhosted.org/packages/59/da/03ec347769c30497580f527004ec99e13e92e75ce635b5d501e129d9c41c/keyweave-0.12.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "8c7aac8a5fe8916aef65016fbdcdd5967d751fec5a66c071c5ea4dc569ad54e0",
                "md5": "20deb9680bd994047e4a628d9b437a9e",
                "sha256": "262b6100640c7c8dbd0d99b391503f3cdef2fa4ae327e1de687d5cb9f2ff131a"
            },
            "downloads": -1,
            "filename": "keyweave-0.12.0.tar.gz",
            "has_sig": false,
            "md5_digest": "20deb9680bd994047e4a628d9b437a9e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.13",
            "size": 13808,
            "upload_time": "2025-08-31T15:39:51",
            "upload_time_iso_8601": "2025-08-31T15:39:51.616191Z",
            "url": "https://files.pythonhosted.org/packages/8c/7a/ac8a5fe8916aef65016fbdcdd5967d751fec5a66c071c5ea4dc569ad54e0/keyweave-0.12.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-31 15:39:51",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "GregRos",
    "github_project": "keyweave",
    "github_not_found": true,
    "lcname": "keyweave"
}
        
Elapsed time: 2.14588s