245 lines
6.1 KiB
ReStructuredText
245 lines
6.1 KiB
ReStructuredText
|
|
Hotkey Service
|
|
==============
|
|
|
|
.. list-table::
|
|
:header-rows: 1
|
|
|
|
* - Technical name
|
|
- Dependencies
|
|
* - ``hotkey``
|
|
- ``ui``
|
|
|
|
|
|
Overview
|
|
--------
|
|
|
|
The ``hotkey`` service offers an easy way to react to a
|
|
fine bounded subset of keyboard inputs: `hotkeys <#hotkey-definition>`_.
|
|
|
|
It provides some very special features:
|
|
|
|
|
|
*
|
|
awareness of the UI active element: no need to worry about that from your side.
|
|
|
|
*
|
|
a clean subset of listenable hotkeys:
|
|
it ensures a consistent experience through different OSes or browsers.
|
|
|
|
*
|
|
a ``useHotkey`` hook: it ensures your JS code executes only
|
|
when your component is alive and present in the DOM.
|
|
|
|
*
|
|
a ``[data-hotkey]`` attribute: it gives a JS-free way to make
|
|
any HTML element "clickable" through an hotkey press.
|
|
|
|
*
|
|
a single key to display overlays over all HTML elements having ``[data-hotkey]`` attributes.
|
|
|
|
Good To Know - ALT is required
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
By default, to trigger an hotkey, it is required to also press the ``ALT`` key:
|
|
|
|
..
|
|
|
|
*e.g.* **ALT+\ *C** would trigger the **C** hotkey.
|
|
|
|
|
|
An option is available to make it optional in some cases. See the `API <#api>`_ section.
|
|
|
|
Good To Know - MAC users
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
To ensure a similar experience to Mac users some keys had to get swapped :
|
|
|
|
.. list-table::
|
|
:header-rows: 1
|
|
|
|
* - Standard Key is...
|
|
- MacOS Corresponding Key is...
|
|
* - ``alt``
|
|
- ``control``
|
|
* - ``control``
|
|
- ``meta`` (known as *Command* by mac users)
|
|
|
|
|
|
Hotkey Definition
|
|
^^^^^^^^^^^^^^^^^
|
|
|
|
An **hotkey** represents as a string a single keyboard
|
|
input from a *single key* combined or not with *modifiers*.
|
|
|
|
.. list-table::
|
|
:header-rows: 1
|
|
|
|
* - Authorized Single Keys
|
|
* - **a-z**
|
|
* - **0-9**
|
|
* - **ArrowUp** , **ArrowLeft** , **ArrowDown** and **ArrowRight**
|
|
* - **PageUp** , **PageDown** , **Home** and **End**
|
|
* - **Backspace** , **Enter** and **Escape**
|
|
|
|
|
|
.. list-table::
|
|
:header-rows: 1
|
|
|
|
* - Authorized Modifiers
|
|
* - **Control**
|
|
* - **Shift**
|
|
|
|
|
|
Hotkeys **must be** written following these rules:
|
|
|
|
|
|
* they are not case sensitive.
|
|
* the composition character is the plus sign: "\ **+** ".
|
|
* each hotkey can have none or any modifier in the authorized subset.
|
|
* order of their parts is important:
|
|
|
|
* modifiers must come first
|
|
* modifiers must get alphabetically sorted (\ **Control** is always before **Shift** )
|
|
* single key part must come last
|
|
|
|
E.g. following hotkeys are valid:
|
|
|
|
|
|
* ``Control+Shift+5``
|
|
* ``g``
|
|
* ``Control+g`` (same as ``Control+G`` )
|
|
|
|
E.g. following hotkeys are **NOT** valid:
|
|
|
|
|
|
* ``Alt+o`` : **alt** is neither a valid modifier nor a valid single key
|
|
* ``o+d`` : combining two or more single keys is not valid
|
|
* ``Shift-p`` : the composition character must be "+" and not "-"
|
|
* ``Tab`` : it is not part of the list of valid single keys, nor modifiers
|
|
|
|
Hotkey Activation
|
|
^^^^^^^^^^^^^^^^^
|
|
|
|
Hotkeys are activated through keyboard inputs.
|
|
|
|
By default, to activate an hotkey, ``ALT`` key should get pressed simultaneously.
|
|
It is also possible to register an hotkey that will be fireable, even without pressing ALT key.
|
|
|
|
When the service detects an hotkey activation, it will:
|
|
|
|
|
|
* execute **all matching registrations callbacks**.
|
|
* click on **all visible elements having a matching ``[data-hotkey]`` attribute**.
|
|
|
|
The ``hotkey`` service will also **make sure that those
|
|
registrations and elements belong to the correct UI active element** (see `\ ``ui`` service <ui.md>`_\ ).
|
|
|
|
API
|
|
---
|
|
|
|
The ``hotkey`` service provides the following API:
|
|
|
|
|
|
*
|
|
``registerHotkey(hotkey: string, callback: ()=>void, options: { altIsOptional?: boolean, allowRepeat?: boolean }): number``
|
|
|
|
it asks the service to call the given callback when a matching hotkey is pressed.
|
|
|
|
``options.altIsOptional`` : default is false.
|
|
|
|
``options.allowRepeat`` : default is false.
|
|
|
|
This method returns a token you can use to unsubscribe later on.
|
|
|
|
*
|
|
``unregisterHotkey(token: number): void``
|
|
|
|
it asks the service to forget about the token matching registration.
|
|
|
|
In addition to that, you have access to some development helpers which are **greatly** recommended:
|
|
|
|
|
|
*
|
|
``useHotkey(hotkey: string, callback: ()=>void, options: { altIsOptional?: boolean, allowRepeat?: boolean }): void``
|
|
|
|
a hook that ensures your registration exists only when your component is mounted.
|
|
|
|
*
|
|
``[data-hotkey]``
|
|
|
|
an HTML attribute taking an hotkey definition.
|
|
|
|
When the defined hotkey is pressed, the element gets clicked.
|
|
|
|
Examples
|
|
--------
|
|
|
|
``useHotkey`` hook
|
|
^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
.. code-block:: js
|
|
|
|
class MyComponent extends Component {
|
|
setup() {
|
|
useHotkey("a", this.onAHotkey.bind(this));
|
|
useHotkey("Home", () => this.onHomeHotkey());
|
|
}
|
|
onAHotkey() { ... }
|
|
onHomeHotkey() { ... }
|
|
}
|
|
|
|
``[data-hotkey]`` attribute
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
.. code-block:: js
|
|
|
|
class MyComponent extends Component {
|
|
setup() {
|
|
this.variableHotkey = "control+j";
|
|
}
|
|
onButton1Clicked() {
|
|
console.log("clicked either with the mouse or with hotkey 'Shift+o'");
|
|
}
|
|
onButton2Clicked() {
|
|
console.log(`clicked either with the mouse or with hotkey '${this.variableHotkey}'`);
|
|
}
|
|
}
|
|
MyComponent.template = xml`
|
|
<div>
|
|
|
|
<button t-on-click="onButton1Clicked" data-hotkey="Shift+o">
|
|
One!
|
|
</button>
|
|
|
|
<button t-on-click="onButton2Clicked" t-att-data-hotkey="variableHotkey">
|
|
Two!
|
|
</button>
|
|
|
|
</div>
|
|
`;
|
|
|
|
manual usage of the service
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
.. code-block:: js
|
|
|
|
class MyComponent extends Component {
|
|
setup() {
|
|
this.hotkey = useService("hotkey");
|
|
}
|
|
mounted() {
|
|
this.hotkeyToken1 = this.hotkey.registerHotkey("backspace", () =>
|
|
console.log("backspace has been pressed")
|
|
);
|
|
this.hotkeyToken2 = this.hotkey.registerHotkey("Shift+P", () =>
|
|
console.log('Someone pressed on "shift+p"!')
|
|
);
|
|
}
|
|
willUnmount() {
|
|
// You need to manually unregister your registrations when needed!
|
|
this.hotkey.unregisterHotkey(this.hotkeyToken1);
|
|
this.hotkey.unregisterHotkey(this.hotkeyToken2);
|
|
}
|
|
}
|