Keyboard shortcuts with RxJS
In this blog post, I’m sharing the TypeScript implementation of a manager class around keyboard shortcuts. It allows to register and deregister keyboard shortcuts for the whole application globally. The implementation was inspired by this great blog post: “Create Keyboard Shortcuts with RxJS”, but I improved the proposed implementation drastically by adding a bug fix and a couple of extensions. Just like in the original blog post, we’re leveraging RxJS. Let’s create a class called ShortcutManager
. What is the purpose of this class? This class provides a single public method shortcut$
which is implemented as follows:
This shortcut function can be used to create Observable
stream for any keyboard shortcut. A keyboard shortcut is a sequence of key codes, each representing a key of keyboard. Usage example as shortcut for Ctrl+F:
The returned stream of keyboard events describes every pressed key. The undefined
in the returned event stream means, all keys have been released. This is handy for some scenarios where you need to track the keyup
events — and this is an extension of the originally proposed implementation in the mentioned blog post. Another examples from my current project:
Of course, we can construct any arbitrary sequence of shortcuts such as shortcut$(ShortcutKey.Alt, ShortcutKey.F1, ShortcutKey.Digit0)
for the three pressed keys “Alt+F1+0”. Most of the time, the order of pressed keys is important, so that the implementation considers the order. In the last example, first the “Alt” key should be pressed, then the “F1” and the “0” digit at the end.
Let’s speak about ShortcutKey
and explore every private method in the ShortcutManager
in details. The class ShortcutKey
represents a single shortcut key. I’m gonna to show an excerpt only. For more details regarding defined constants see the official documentation “Code values for keyboard events” and the property “code” there.
Please see the comments — for the sake of convenience, we don’t need to list different physical keys like “AltLeft” and “AltRight” for a single logical key. We can use a logical key “Alt” and shorten the syntax for key registration. This is a handy extension in comparison to the original blog post. To achieve this goal I added a method which generates cartesian product (see the method invocation in the public shortcut$
).
Another two private methods are listed below:
As you see, we buffer pressed keys to be able to check later if all of them are released. This is a bug fix I mentioned above. The combineLatest
RxJS operator waits for all input (= pressed keys) and emit all the latest values of all inputs. The registration of keydown
and keyup
keyboard events occurs on the document
object by means of the fromEvent
RxJS operator.
The last remaining private method checkPressedKey
(used within the filter
) is a check for the exactly count of the pressed keys. As you see, as soon as all keys get released, the subscribers of theshortcut$
will be informed. It also check the key sequence, i.e. order of the pressed keys. It is a requirement here, but was an optional add-on in the original implementation.
That’s all. Give it a try!