# keymage
**Repository Path**: mirrors_GerHobbelt/keymage
## Basic Information
- **Project Name**: keymage
- **Description**: Yet Another JS Keybinding library
- **Primary Language**: Unknown
- **License**: ISC
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-08-08
- **Last Updated**: 2025-06-02
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# keymage.js
Keymage is a small (1.5kb min.gz) library for handling key bindings in
JavaScript. It supports nested application scopes, has a simple DSL for defining
keys and can handle key chords.
[](https://travis-ci.org/piranha/keymage) - or [check tests](https://rawgithub.com/piranha/keymage/master/test/test.html) in browser
## Features
- Simple language for defining bindings
- Key sequences (a-la Emacs chords)
- Nested scopes
- Default modifier (`defmod` key which is `command` on OS X and `control`
elsewhere)
- Ability to prevent defaults for whole sequence
## Usage
Include `keymage.min.js` in your page:
```html
```
There are no dependencies. It is possible to use library as a simple JS module,
as an AMD module or as CommonJS module.
It worth to note that [Keymage is on cdnjs](http://cdnjs.com/libraries/keymage/)
and you can use it without downloading:
```html
```
Plus, of course, it's on [NPM](https://www.npmjs.org/package/keymage).
## Defining shortcuts
Keymage exposes a single function, `keymage`:
```javascript
// bind on 'a'
keymage('a', function() { alert("You pressed 'a'"); });
// returning false prevents default browser reaction (you can always use
// e.preventDefault(), of course)
keymage('ctrl-e', function() { return false; });
// binding on 'defmod' binds on Command key on OS X and on Control key in other
// systems
keymage('defmod-j', function() { alert("I am fired"); });
```
Handler function receives two arguments: the original event and the context so
you can understand what and why was fired.
The context contains those properties:
- `shortcut` is a string you've originally provided for binding
- `scope` is a scope which is currently active
- `definitionScope` is a scope where this shortcut was defined
```javascript
keymage('alt-c', function(e, ctx) {
console.log(ctx.shortcut, ctx.scope, ctx.definitionScope);
});
// -> "alt-c", "", ""
```
## Sequences
Keymage supports key sequences:
```javascript
keymage('ctrl-j k', function() { alert("Nice!"); });
```
For this to fire you have to first press both `ctrl` and `j`, and then
`k`. Here's the catch though: `ctrl-j` in most browsers means "open
downloads". Which will break your sequence obviously.
And while I encourage you to not override browser hotkeys, let's imagine you
have to do that. For this, you can pass an option object as last parameter,
having 'preventDefault' property set to `true`:
```javascript
keymage('ctrl-t ctrl-j k',
function() { alert("wow"); },
{preventDefault: true});
```
This option will prevent default on every key press which looks like a valid
part of a bound sequence (including the one triggering your handler). And in
this case it's perfectly legitimate - you're overriding `ctrl-j` in the middle
of sequence, so common browser hotkey will still work.
## Scopes
Keymage support nested scopes. This means that your application can have few
areas where you can gradually have more and more specific shortcuts. It works
like this:
```javascript
// You can skip scope argument if you want global work-always shortcut
keymage('ctrl-j q', function() { alert("Default scope"); });
// This will fire after "keymage.setScope('chat')"
keymage('chat', 'ctrl-j w', function() { alert("Chat scope"); });
// This will fire after "keymage.setScope('chat.input')"
keymage('chat.input', 'ctrl-j e', function() { alert("Chat.input scope"); });
```
You can control scopes with helpful `pushScope` and `popScope` methods. This way
your nested view (or whatever is enabling nested scope) doesn't need to know
about parent scope:
```javascript
keymage.pushScope('chat') // scope is 'chat'
keymage.pushScope('input') // scope is 'chat.input'
keymage.popScope() // scope is 'chat'
keymage.pushScope('deep')
keymage.pushScope('deeper') // scope is 'chat.deep.deeper'
// way to jump out of deep scoping
keymage.popScope('chat') // scope is ''
```
`pushScope` returns resulting scope and `popScope` returns topmost scope it
removed (so with parameters it's the one you've asked to remove).
Note that calling `popScope` with name of a scope which is repeated few times
will pop topmost one, i.e.:
```javascript
keymage.setScope('this.scope.is.deep.scope')
keymage.popScope('scope') // scope is 'this'
```
## Options
Last and optional argument to `keymage` function is an option object. Here is a
list of possible options:
- `preventDefault`: when `true`, calls `event.preventDefault()` on every key
press which looks like a part of defined sequence.
- `context`: binding handler will be called with provided object as a context.
## Unbinding
And if you ever need to unbind a handler, use this:
```javascript
keymage.unbind('ctrl-j k', your_handler_function);
```