{"id":13509219,"url":"https://github.com/piranha/keymage","last_synced_at":"2025-04-05T05:10:08.289Z","repository":{"id":5808731,"uuid":"7023606","full_name":"piranha/keymage","owner":"piranha","description":"Yet Another JS Keybinding library","archived":false,"fork":false,"pushed_at":"2016-06-30T12:30:40.000Z","size":70,"stargazers_count":330,"open_issues_count":4,"forks_count":27,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-03-29T04:09:21.670Z","etag":null,"topics":["hotkey","hotkeys","javascript","shortcut","shortcuts"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/piranha.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-12-05T19:53:54.000Z","updated_at":"2025-03-22T12:27:40.000Z","dependencies_parsed_at":"2022-08-24T21:30:38.284Z","dependency_job_id":null,"html_url":"https://github.com/piranha/keymage","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piranha%2Fkeymage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piranha%2Fkeymage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piranha%2Fkeymage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piranha%2Fkeymage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/piranha","download_url":"https://codeload.github.com/piranha/keymage/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247289429,"owners_count":20914464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hotkey","hotkeys","javascript","shortcut","shortcuts"],"created_at":"2024-08-01T02:01:04.743Z","updated_at":"2025-04-05T05:10:08.246Z","avatar_url":"https://github.com/piranha.png","language":"JavaScript","readme":"# keymage.js\n\nKeymage is a small (1.6kb after Closure Compiler and gzip) library for handling\nkey bindings in JavaScript. It supports nested application scopes, has a simple\nDSL for defining keys and can handle key chords.\n\n[![Build Status](https://travis-ci.org/piranha/keymage.svg?branch=master)](https://travis-ci.org/piranha/keymage) - or [check tests](https://rawgit.com/piranha/keymage/master/test/test.html) in browser\n\n## Features\n\n - Simple language for defining bindings\n - Key sequences (a-la Emacs chords)\n - Nested scopes\n - Default modifier (`defmod` key which is `command` on OS X and `control`\n   elsewhere)\n - Ability to prevent defaults for whole sequence\n\n\n## Usage\n\nInclude `keymage.min.js` in your page:\n\n```html\n\u003cscript src=\"keymage.min.js\"\u003e\u003c/script\u003e\n```\n\nThere are no dependencies. It is possible to use library as a simple JS module,\nas an AMD module or as CommonJS module.\n\nIt worth to note that [Keymage is on cdnjs](http://cdnjs.com/libraries/keymage/)\nwhich enables you to use it without downloading.\n\nPlus, of course, it's on [NPM](https://www.npmjs.org/package/keymage).\n\n## Defining shortcuts\n\nKeymage exposes a single function, `keymage`:\n\n```javascript\n// bind on 'a'\nkeymage('a', function() { alert(\"You pressed 'a'\"); });\n\n// returning false prevents default browser reaction (you can always use\n// e.preventDefault(), of course)\nkeymage('ctrl-e', function() { return false; });\n\n// binding on 'defmod' binds on Command key on OS X and on Control key in other\n// systems\nkeymage('defmod-j', function() { alert(\"I am fired\"); });\n```\n\nHandler function receives two arguments: the original event and the context so\nyou can understand what and why was fired.\n\nThe context contains those properties:\n\n - `shortcut` is a string you've originally provided for binding\n - `scope` is a scope which is currently active\n - `definitionScope` is a scope where this shortcut was defined\n\n```javascript\nkeymage('alt-c', function(e, ctx) {\n    console.log(ctx.shortcut, ctx.scope, ctx.definitionScope);\n});\n\n// -\u003e \"alt-c\", \"\", \"\"\n```\n\n## Sequences\n\nKeymage supports key sequences:\n\n```javascript\nkeymage('ctrl-k j', function() { alert(\"Nice!\"); });\n```\n\nFor this to fire you have to first press both `ctrl` and `k`, and then\n`j`. This will fire an alert.\n\nThere is something to remember: browsers have their own shortcuts, for example\n`ctrl-j` in most browsers means \"open downloads\". And while you can always call\n`e.preventDefault()` in usual situation, if `ctrl-j` is part of a sequence, it's\nnot that easy - you'll get control over what's happening only when the whole\nsequence is pressed.\n\nSo keymage provides you with a means to support this use case. I do not\nencourage you to override browser hotkeys, but let's imagine you want to do\nthat. For this, you can pass an option object as last parameter, having\n`preventDefault` property set to `true`:\n\n```javascript\nkeymage('ctrl-t ctrl-j k',\n        function() { alert(\"wow\"); },\n        {preventDefault: true});\n```\n\nThis option will prevent default on *every* key press which is a valid part of a\nbound sequence, including the one triggering your handler. Note that pressing\nonly `ctrl-j` (without `ctrl-t`) will still open downloads, keymage looks for\nsequence of `ctrl-t ctrl-j`.\n\n## Scopes\n\nKeymage support nested scopes. This means that your application can have few\nareas where you can gradually have more and more specific shortcuts. It works\nlike this:\n\n```javascript\n// You can skip scope argument if you want global work-always shortcut\nkeymage('ctrl-j q', function() { alert(\"Default scope\"); });\n\n// This will fire after \"keymage.setScope('chat')\"\nkeymage('chat', 'ctrl-j w', function() { alert(\"Chat scope\"); });\n\n// This will fire after \"keymage.setScope('chat.input')\"\nkeymage('chat.input', 'ctrl-j e', function() { alert(\"Chat.input scope\"); });\n```\n\nYou can control scopes with helpful `pushScope` and `popScope` methods. This way\nyour nested view (or whatever is enabling nested scope) doesn't need to know\nabout parent scope:\n\n```javascript\nkeymage.pushScope('chat') // scope is 'chat'\n\nkeymage.pushScope('input') // scope is 'chat.input'\n\nkeymage.popScope() // scope is 'chat'\n\nkeymage.pushScope('deep')\nkeymage.pushScope('deeper') // scope is 'chat.deep.deeper'\n\n// way to jump out of deep scoping\nkeymage.popScope('chat') // scope is ''\n```\n\n`pushScope` returns resulting scope and `popScope` returns topmost scope it\nremoved (so with parameters it's the one you've asked to remove).\n\nNote that calling `popScope` with name of a scope which is repeated few times\nwill pop topmost one, i.e.:\n\n```javascript\nkeymage.setScope('this.scope.is.deep.scope')\nkeymage.popScope('scope') // scope is 'this'\n```\n\n\n## Options\n\nLast and optional argument to `keymage` function is an option object. Here is a\nlist of possible options:\n\n - `preventDefault`: when `true`, calls `event.preventDefault()` on every key\n   press which looks like a part of defined sequence.\n\n - `context`: binding handler will be called with provided object as a context.\n\n\n## Unbinding\n\nAnd if you ever need to unbind a handler, use this:\n\n```javascript\nkeymage.unbind('ctrl-j k', your_handler_function);\n```\n\nAlso, `keymage(...)` returns a function, which unbinds this shortcut when called:\n\n```javascript\nvar unbinder = keymage('ctrl-j k', your_handler_function);\nunbinder();\n```\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiranha%2Fkeymage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpiranha%2Fkeymage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiranha%2Fkeymage/lists"}