├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ └── pr.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .kktrc.js ├── LICENSE ├── README-zh.md ├── README.md ├── dist ├── README.md ├── hotkeys.common.js ├── hotkeys.common.min.js ├── hotkeys.esm.js ├── hotkeys.js └── hotkeys.min.js ├── index.d.ts ├── index.js ├── package-lock.json ├── package.json ├── public └── index.html ├── scripts ├── build.mjs └── watch.mjs ├── src ├── .babelrc ├── index.js ├── utils.js └── var.js ├── test ├── index.html └── run.test.js └── website ├── App.js ├── assets └── bg.jpg ├── components ├── Footer.js └── Footer.module.less ├── index.js └── styles ├── index.module.less └── reset.less /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | coverage -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "env": { 4 | "browser": true, 5 | "node": true, 6 | "es6": true, 7 | "mocha": true, 8 | "jest": true, 9 | "jasmine": true 10 | }, 11 | "rules": { 12 | "object-curly-newline": 0, 13 | "linebreak-style": 0, 14 | "arrow-body-style": 0, 15 | "max-len": 0, 16 | "consistent-return": 0, 17 | "generator-star-spacing": 0, 18 | "global-require": 1, 19 | "import/extensions": 0, 20 | "import/no-extraneous-dependencies": 0, 21 | "import/no-unresolved": 0, 22 | "import/prefer-default-export": 0, 23 | "jsx-a11y/no-noninteractive-element-interactions": 0, 24 | "jsx-a11y/no-static-element-interactions": 0, 25 | "no-bitwise": 0, 26 | "no-cond-assign": 0, 27 | "no-else-return": 0, 28 | "no-param-reassign": 0, 29 | "no-nested-ternary": 0, 30 | "no-restricted-syntax": 0, 31 | "no-use-before-define": 0, 32 | "react/no-array-index-key": 0, 33 | "react/forbid-prop-types": 0, 34 | "react/jsx-filename-extension": [ 35 | 1, 36 | { 37 | "extensions": [ 38 | ".js" 39 | ] 40 | } 41 | ], 42 | "react/jsx-no-bind": 0, 43 | "react/prefer-stateless-function": 0, 44 | "react/prop-types": 0, 45 | "require-yield": 1, 46 | "no-console": [ 47 | "error", 48 | { 49 | "allow": [ 50 | "log" 51 | ] 52 | } 53 | ], 54 | "class-methods-use-this": 0, 55 | "no-confusing-arrow": 0, 56 | "react/sort-comp": 0, 57 | "no-unused-expressions": 0, 58 | "no-underscore-dangle": 0, 59 | "no-plusplus": 0, 60 | "react/no-did-mount-set-state": 0 61 | }, 62 | "parserOptions": { 63 | "parser": "@babel/eslint-parser", 64 | "requireConfigFile": false, 65 | "ecmaVersion": 8, 66 | "ecmaFeatures": { 67 | "experimentalObjectRestSpread": true 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: jaywcjlove 2 | buy_me_a_coffee: jaywcjlove 3 | custom: ["https://www.paypal.me/kennyiseeyou", "https://jaywcjlove.github.io/#/sponsor"] 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | tags: 7 | - v* 8 | 9 | env: 10 | SKIP_PREFLIGHT_CHECK: true 11 | 12 | jobs: 13 | build-deploy: 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: write 17 | id-token: write 18 | steps: 19 | - uses: actions/checkout@v4 20 | - uses: actions/setup-node@v4 21 | with: 22 | node-version: 20 23 | registry-url: 'https://registry.npmjs.org' 24 | 25 | # - name: Cache dependencies 26 | # uses: actions/cache@v1 27 | # with: 28 | # path: ~/.npm 29 | # key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 30 | # restore-keys: | 31 | # ${{ runner.os }}-node- 32 | 33 | - name: Look Changelog 34 | uses: jaywcjlove/changelog-generator@main 35 | with: 36 | token: ${{ secrets.GITHUB_TOKEN }} 37 | filter-author: (jaywcjlove|小弟调调™|dependabot\[bot\]|Renovate Bot) 38 | filter: (^[\s]+?[R|r]elease)|(^[R|r]elease) 39 | 40 | - run: npm install 41 | - run: npm run build 42 | - run: npm run test 43 | 44 | - name: Generate Contributors Images 45 | uses: jaywcjlove/github-action-contributors@main 46 | with: 47 | filter-author: (renovate\[bot\]|renovate-bot|dependabot\[bot\]) 48 | output: build/CONTRIBUTORS.svg 49 | avatarSize: 42 50 | 51 | - name: Create Tag 52 | id: create_tag 53 | uses: jaywcjlove/create-tag-action@main 54 | with: 55 | package-path: ./package.json 56 | 57 | - name: get tag version 58 | id: tag_version 59 | uses: jaywcjlove/changelog-generator@main 60 | 61 | - name: Build and Deploy 62 | uses: peaceiris/actions-gh-pages@v4 63 | with: 64 | commit_message: ${{steps.tag_version.outputs.tag}} ${{ github.event.head_commit.message }} 65 | github_token: ${{ secrets.GITHUB_TOKEN }} 66 | publish_dir: ./build 67 | 68 | - name: Generate Changelog 69 | id: changelog 70 | uses: jaywcjlove/changelog-generator@main 71 | with: 72 | token: ${{ secrets.GITHUB_TOKEN }} 73 | filter-author: (jaywcjlove|小弟调调™|dependabot\[bot\]|Renovate Bot) 74 | filter: (^[\s]+?[R|r]elease)|(^[R|r]elease) 75 | 76 | - run: | 77 | echo "tag: ${{ steps.changelog.outputs.tag }}" 78 | echo "version: ${{ steps.changelog.outputs.version }}" 79 | echo "ref: ${{ github.ref }}" 80 | 81 | - name: Create Release 82 | uses: ncipollo/release-action@v1 83 | if: steps.create_tag.outputs.successful 84 | with: 85 | allowUpdates: true 86 | token: ${{ secrets.GITHUB_TOKEN }} 87 | name: ${{ steps.create_tag.outputs.version }} 88 | tag: ${{ steps.create_tag.outputs.version }} 89 | body: | 90 | [![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-048754?logo=buymeacoffee)](https://jaywcjlove.github.io/#/sponsor) [![](https://img.shields.io/badge/Open%20in-unpkg-blue)](https://uiwjs.github.io/npm-unpkg/#/pkg/hotkeys-js@${{steps.changelog.outputs.version}}/file/README.md) [![npm bundle size](https://img.shields.io/bundlephobia/minzip/hotkeys-js)](https://bundlephobia.com/result?p=hotkeys-js@${{steps.changelog.outputs.version}}) [![npm version](https://img.shields.io/npm/v/hotkeys-js.svg)](https://www.npmjs.com/package/hotkeys-js) 91 | 92 | Documentation ${{ steps.changelog.outputs.tag }}: https://raw.githack.com/jaywcjlove/hotkeys/${{ steps.changelog.outputs.gh-pages-short-hash }}/index.html 93 | Comparing Changes: ${{ steps.changelog.outputs.compareurl }} 94 | 95 | ```bash 96 | npm i hotkeys-js@${{steps.changelog.outputs.version}} 97 | ``` 98 | 99 | ${{ steps.changelog.outputs.changelog }} 100 | 101 | - name: package.json info 102 | uses: jaywcjlove/github-action-package@main 103 | with: 104 | unset: browserslist,lint-staged,devDependencies,jest,scripts 105 | 106 | # - run: npm install @jsdevtools/npm-publish -g 107 | # - run: npm-publish --token="${{ secrets.NPM_TOKEN }}" ./package.json 108 | - run: npm publish --access public --provenance 109 | name: 📦 hotkeys-js to NPM 110 | continue-on-error: true 111 | env: 112 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: CI-PR 2 | on: 3 | pull_request: 4 | 5 | env: 6 | SKIP_PREFLIGHT_CHECK: true 7 | 8 | jobs: 9 | build-deploy: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: write 13 | id-token: write 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: actions/setup-node@v4 17 | with: 18 | node-version: 20 19 | registry-url: 'https://registry.npmjs.org' 20 | 21 | - name: Look Changelog 22 | uses: jaywcjlove/changelog-generator@main 23 | with: 24 | token: ${{ secrets.GITHUB_TOKEN }} 25 | filter-author: (jaywcjlove|小弟调调™|dependabot\[bot\]|Renovate Bot) 26 | filter: (^[\s]+?[R|r]elease)|(^[R|r]elease) 27 | 28 | - run: npm install 29 | - run: npm run build 30 | - run: npm run test 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | yarn.lock 3 | node_modules 4 | build 5 | doc 6 | coverage 7 | 8 | .DS_Store 9 | .cache 10 | .vscode 11 | .idea 12 | 13 | *.bak 14 | *.tem 15 | *.temp 16 | #.swp 17 | *.*~ 18 | ~*.* 19 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.kktrc.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import webpack from 'webpack'; 3 | import lessModules from '@kkt/less-modules'; 4 | import rawModules from '@kkt/raw-modules'; 5 | import { disableScopePlugin } from '@kkt/scope-plugin-options'; 6 | import scopePluginOptions from '@kkt/scope-plugin-options'; 7 | import pkg from './package.json'; 8 | 9 | export default (conf, env, options) => { 10 | conf = lessModules(conf, env, options); 11 | conf = rawModules(conf, env, options); 12 | conf = disableScopePlugin(conf); 13 | conf = scopePluginOptions(conf, env, { 14 | ...options, 15 | allowedFiles: [ 16 | path.resolve(process.cwd(), 'README.md'), 17 | path.resolve(process.cwd(), 'src') 18 | ], 19 | }); 20 | conf.ignoreWarnings = [ 21 | { module: /node_modules[\\/]parse5[\\/]/ } 22 | ]; 23 | // Get the project version. 24 | conf.plugins.push( 25 | new webpack.DefinePlugin({ 26 | VERSION: JSON.stringify(pkg.version), 27 | }) 28 | ); 29 | 30 | if (env === 'production') { 31 | conf.optimization = { 32 | ...conf.optimization, 33 | splitChunks: { 34 | cacheGroups: { 35 | reactvendor: { 36 | test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/, 37 | name: 'react-vendor', 38 | chunks: 'all', 39 | }, 40 | refractor: { 41 | test: /[\\/]node_modules[\\/](refractor)[\\/]/, 42 | name: 'refractor-vendor', 43 | chunks: 'all', 44 | }, 45 | }, 46 | }, 47 | }; 48 | conf.output = { ...conf.output, publicPath: './' }; 49 | } 50 | return conf; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015-present, Kenny Wong. 4 | 5 | Copyright (c) 2011-2013 Thomas Fuchs (https://github.com/madrobby/keymaster) 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /README-zh.md: -------------------------------------------------------------------------------- 1 | # Hotkeys 2 | 3 | [![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-048754?logo=buymeacoffee)](https://jaywcjlove.github.io/#/sponsor) 4 | [![npm dowload](https://img.shields.io/npm/dm/hotkeys-js?logo=npm)](https://www.npmjs.com/package/hotkeys-js) 5 | [![Stargazers](https://img.shields.io/github/stars/jaywcjlove/hotkeys.svg)](https://github.com/jaywcjlove/hotkeys/stargazers) 6 | ![no dependencies](http://jaywcjlove.github.io/sb/status/no-dependencies.svg) 7 | [![GitHub Actions CI](https://github.com/jaywcjlove/hotkeys/actions/workflows/ci.yml/badge.svg)](https://github.com/jaywcjlove/hotkeys/actions/workflows/ci.yml) 8 | [![Coverage Status](https://coveralls.io/repos/github/jaywcjlove/hotkeys/badge.svg?branch=master)](https://coveralls.io/github/jaywcjlove/hotkeys?branch=master) 9 | [![English](https://jaywcjlove.github.io/sb/lang/english.svg)](https://jaywcjlove.github.io/hotkeys-js/) 10 | [![for Gitee](https://jaywcjlove.github.io/sb/ico/gitee.svg)](https://gitee.com/jaywcjlove/hotkeys) 11 | 12 | 这是一个强健的 Javascript 库用于捕获键盘输入和输入的组合键,它易于使用,没有依赖,压缩只有([~6kB](https://bundlephobia.com/result?p=hotkeys-js)),gzip: **`2.8kB`**。[官方文档DEMO预览](http://jaywcjlove.github.io/hotkeys-js/?lang=cn),[更多实例](https://github.com/jaywcjlove/hotkeys/issues?q=label%3ADemo+)。 13 | 14 | 15 | ```shell 16 | ╭┈┈╮ ╭┈┈╮ ╭┈┈╮ 17 | ┆ ├┈┈..┈┈┈┈┈.┆ └┈╮┆ ├┈┈..┈┈┈┈┈..┈┈.┈┈..┈┈┈┈┈. 18 | ┆ ┆┆ □ ┆┆ ┈┤┆ < ┆ -__┘┆ ┆ ┆┆__ ┈┈┤ 19 | ╰┈┈┴┈┈╯╰┈┈┈┈┈╯╰┈┈┈┈╯╰┈┈┴┈┈╯╰┈┈┈┈┈╯╰┈┈┈ ┆╰┈┈┈┈┈╯ 20 | ╰┈┈┈┈┈╯ 21 | ``` 22 | 23 | ## 创建 24 | 25 | 您将需要在您的系统上安装的 Node.js。 26 | 27 | ```sh 28 | # bower 安装 29 | $ bower install hotkeysjs 30 | 31 | # npm 安装 32 | $ npm install hotkeys-js 33 | 34 | $ npm run build # 编译 35 | $ npm run watch # 开发模式 36 | ``` 37 | 38 | ```js 39 | import hotkeys from 'hotkeys-js'; 40 | 41 | hotkeys('f5', function(event, handler){ 42 | // Prevent the default refresh event under WINDOWS system 43 | event.preventDefault() 44 | alert('you pressed F5!') 45 | }); 46 | ``` 47 | 48 | 或者在您的HTML中手动下载并引入 **hotkeys.js**,你也可以通过 [UNPKG](https://unpkg.com/hotkeys-js/dist/) 进行下载: 49 | 50 | CDN: [UNPKG](https://unpkg.com/hotkeys-js/dist/) | [jsDelivr](https://cdn.jsdelivr.net/npm/hotkeys-js@3.7.3/) | [Githack](https://raw.githack.com/jaywcjlove/hotkeys/master/dist/hotkeys.min.js) | [Statically](https://cdn.statically.io/gh/jaywcjlove/hotkeys/master/dist/hotkeys.min.js) | [bundle.run](https://bundle.run/hotkeys-js@3.7.3) 51 | 52 | ```html 53 | 54 | 64 | ``` 65 | 66 | ## React中使用 67 | 68 | [react-hotkeys](https://github.com/jaywcjlove/react-hotkeys) 是 React 组件,用于侦听 keydown 和 keyup 键盘事件,定义和分配键盘快捷键。 详细的使用方法请参见其文档,详细使用方法请参考文档 [react-hotkeys](https://github.com/jaywcjlove/react-hotkeys)。 69 | 70 | [react-hotkeys-hook](https://github.com/JohannesKlauss/react-hotkeys-hook) - React Hook,用于在组件中使用键盘快捷键。确保您至少安装了 16.8 版本的 react 和 react-dom,否则钩子将对您不起作用。 71 | 72 | ## 使用 73 | 74 | 传统调用 75 | 76 | ```html 77 | 78 | ``` 79 | 80 | 包加载 81 | 82 | ```js 83 | import hotkeys from 'hotkeys-js'; 84 | 85 | hotkeys('shift+a,alt+d, w', function(e){ 86 | console.log('干点活儿',e); 87 | if(hotkeys.shift) console.log('大哥你摁下了 shift 键!'); 88 | if(hotkeys.ctrl) console.log('大哥你摁下了 ctrl 键!'); 89 | if(hotkeys.alt) console.log('大哥你摁下了 alt 键!'); 90 | }); 91 | ``` 92 | 93 | ## 支持的键 94 | 95 | `⇧`, `shift`, `option`, `⌥`, `alt`, `ctrl`, `control`, `command`, `⌘` 96 | 97 | `⌘` Command() 98 | `⌃` Control 99 | `⌥` Option(alt) 100 | `⇧` Shift 101 | `⇪` Caps Lock(大写) 102 | ~~`fn` 功能键就是fn(不支持)~~ 103 | `↩︎` return/enter 104 | `space` 空格键 105 | 106 | ## 修饰键判断 107 | 108 | 可以对下面的修饰键判断 `shift` `alt` `option` `ctrl` `control` `command`,特别注意`+`和`=`键值相同,组合键设置`⌘+=` 109 | 110 | ```js 111 | hotkeys('shift+a,alt+d, w', function(e){ 112 | console.log('干点活儿',e); 113 | if(hotkeys.shift) console.log('您摁下了 shift 键!'); 114 | if(hotkeys.ctrl) console.log('您摁下了 ctrl 键!'); 115 | if(hotkeys.alt) console.log('您摁下了 alt 键!'); 116 | if(hotkeys.option) console.log('您摁下了 option 键!'); 117 | if(hotkeys.control) console.log('您摁下了 control 键!'); 118 | if(hotkeys.cmd) console.log('您摁下了 cmd 键!'); 119 | if(hotkeys.command) console.log('您摁下了 command 键!'); 120 | }); 121 | ``` 122 | 123 | ## 定义快捷键 124 | 125 | > `hotkeys([keys:], [option:[string|object|function]], [callback:])` 126 | 127 | ```js 128 | // 定义 F5 快捷键 129 | hotkeys('f5', function(event,handler){ 130 | //event.srcElement: input 131 | //event.target: input 132 | // 阻止WINDOWS系统下的默认刷新事件 133 | event.preventDefault() 134 | alert('你按下了 F5 键!') 135 | }); 136 | // 返回 false 将停止活动,并阻止默认浏览器事件 137 | // Mac OS 系统 定义 `command+r` 为刷新快捷键 138 | hotkeys('ctrl+r, command+r', function(){ 139 | alert('停止刷新!'); 140 | return false; 141 | }); 142 | 143 | // 定义a快捷键 144 | hotkeys('a', function(event,handler){ 145 | //event.srcElement: input 146 | //event.target: input 147 | if(event.target === "input"){ 148 | alert('你在输入框中按下了 a!') 149 | } 150 | alert('你按下了 a!') 151 | }); 152 | 153 | // 定义 ctrl+a、ctrl+b、r、f 四组快捷键 154 | hotkeys('ctrl+a,ctrl+b,r,f', function(event,handler){ 155 | switch(handler.key){ 156 | case "ctrl+a": alert('你按下了ctrl+a!'); break; 157 | case "ctrl+b": alert('你按下了ctrl+b!'); break; 158 | case "r": alert('你按下了r!'); break; 159 | case "f": alert('你按下了f!'); break; 160 | } 161 | //handler.scope 范围 162 | }); 163 | 164 | 165 | // 多个快捷方式做同样的事情 166 | hotkeys('⌘+r, ctrl+r', function(){ }); 167 | 168 | // 对所有摁键执行任务 169 | hotkeys('*','wcj', function(e){ 170 | console.log('干点活儿',e); 171 | console.log("key.getScope()::",hotkeys.getScope()); 172 | if(hotkeys.shift) console.log('大哥你摁下了 shift 键!'); 173 | if(hotkeys.ctrl) console.log('大哥你摁下了 ctrl 键!'); 174 | if(hotkeys.alt) console.log('大哥你摁下了 alt 键!'); 175 | }); 176 | 177 | // 可以设置自定义的分割符 178 | hotkeys('ctrl-y, ctrl-a', {splitKey: '-'}, function(e){ 179 | console.log('you press bind keys') 180 | }) 181 | ``` 182 | 183 | #### option 184 | 185 | - `scope`:设置快捷键的作用范围 186 | - `element`:指定要绑定事件的 DOM 节点 187 | - `keyup`:是否在按键抬起时触发快捷键 188 | - `keydown`:是否在按键按下时触发快捷键 189 | - `splitKey`:组合键的分隔符(默认值为 `+`) 190 | - `capture`:是否在事件捕获阶段触发监听器(即事件向下传播前) 191 | - `single`:是否只允许一个回调函数(启用时将先执行 unbind) 192 | 193 | 194 | ```js 195 | hotkeys('o, enter', { 196 | scope: 'wcj', 197 | element: document.getElementById('warpper'), 198 | }, function(){ 199 | console.log('do something else'); 200 | }); 201 | 202 | hotkeys('ctrl-+', { splitKey: '-' }, function(e) { 203 | console.log('you pressed ctrl and +'); 204 | }); 205 | 206 | hotkeys('+', { splitKey: '-' }, function(e){ 207 | console.log('you pressed +'); 208 | }) 209 | ``` 210 | 211 | **keyup** 212 | 213 | **key down** 和 **key up** 将都执行回调事件。 214 | 215 | ```js 216 | hotkeys('ctrl+a,alt+a+s', { keyup: true }, (evn, handler) => { 217 | if(evn.type === 'keydown') { 218 | console.log('keydown:', evn.type, handler, handler.key); 219 | } 220 | if(evn.type === 'keyup') { 221 | console.log('keyup:', evn.type, handler, handler.key); 222 | } 223 | }); 224 | ``` 225 | 226 | ## API 参考 227 | 228 | ### 星号 * 229 | 230 | 通过修饰符号判断 231 | 232 | ```js 233 | hotkeys('*', function() { 234 | if (hotkeys.shift) { 235 | console.log('shift is pressed!'); 236 | } 237 | 238 | if (hotkeys.ctrl) { 239 | console.log('ctrl is pressed!'); 240 | } 241 | 242 | if (hotkeys.alt) { 243 | console.log('alt is pressed!'); 244 | } 245 | 246 | if (hotkeys.option) { 247 | console.log('option is pressed!'); 248 | } 249 | 250 | if (hotkeys.control) { 251 | console.log('control is pressed!'); 252 | } 253 | 254 | if (hotkeys.cmd) { 255 | console.log('cmd is pressed!'); 256 | } 257 | 258 | if (hotkeys.command) { 259 | console.log('command is pressed!'); 260 | } 261 | }); 262 | ``` 263 | 264 | ### 切换快捷键 265 | 266 | 如果在单页面在不同的区域,相同的快捷键,干不同的事儿,之间来回切换。O(∩_∩)O ! 267 | 268 | ```js 269 | // 一个快捷键,有可能干的活儿不一样哦 270 | hotkeys('ctrl+o, ctrl+alt+enter', 'scope1', function(){ 271 | console.log('你好看'); 272 | }); 273 | 274 | hotkeys('ctrl+o, enter', 'scope2', function(){ 275 | console.log('你好丑陋啊!'); 276 | }); 277 | 278 | // 你摁 “ctrl+o”组合键 279 | // 当scope等于 scope1 ,执行 回调事件打印出 “你好看”, 280 | // 当scope等于 scope2 ,执行 回调事件打印出 “你好丑陋啊!”, 281 | 282 | // 通过setScope设定范围scope 283 | hotkeys.setScope('scope1'); // 默认所有事儿都干哦 284 | ``` 285 | 286 | ### 标记快捷键范围 287 | 288 | **删除** 区域范围标记 289 | 290 | ```js 291 | hotkeys.deleteScope('scope1'); 292 | ``` 293 | 294 | **获取** 区域范围标记 295 | 296 | ```js 297 | hotkeys.getScope(); 298 | ``` 299 | 300 | **设置** 区域范围标记 301 | 302 | ```js 303 | hotkeys.setScope('scope1'); 304 | ``` 305 | 306 | ### trigger 307 | 308 | ```js 309 | hotkeys.trigger('ctrl+o') 310 | hotkeys.trigger('ctrl+o', 'scope2') 311 | ``` 312 | 313 | ### 解除绑定 314 | 315 | `hotkeys.unbind()` 解除绑定的所有快捷键 316 | `hotkeys.unbind("ctrl+o, ctrl+alt+enter")` 解除绑定两组快捷键 317 | `hotkeys.unbind("ctrl+o","files")` 解除绑定名字叫files的区域范围中的一组快捷键 318 | 319 | ```js 320 | // 解除绑定 'a' 程序函数 321 | hotkeys.unbind('a'); 322 | 323 | // 仅针对单个范围解除绑定快捷键 324 | // 如果未指定范围,则默认为当前范围(hotkeys.getScope()) 325 | hotkeys.unbind('o, enter', 'issues'); 326 | hotkeys.unbind('o, enter', 'files'); 327 | ``` 328 | 329 | 通过函数来解除绑定 330 | 331 | ```js 332 | function example(){} 333 | hotkeys('a', example); 334 | hotkeys.unbind('a', example); 335 | 336 | hotkeys('a', 'issues', example); 337 | hotkeys.unbind('a', 'issues', example); 338 | ``` 339 | 340 | 可以通过传入对象解除绑定的快捷键 341 | 342 | ```js 343 | hotkeys.unbind({ 344 | key: 'ctrl-e,ctrl-u', 345 | scope: 'issues', 346 | spitKey: '-' 347 | }) 348 | ``` 349 | 350 | 传入数组可同时解除多个scope下绑定的快捷键 351 | 352 | ```js 353 | hotkeys.unbind([ 354 | { 355 | key: 'a, ctrl+r', 356 | scope: 'issues', 357 | }, 358 | { 359 | key: '+, ctrl-y', 360 | scope: 'test', 361 | splitKey: '-' 362 | } 363 | ]) 364 | ``` 365 | 366 | ### isPressed 367 | 368 | 判断摁下的键是否为某个键 369 | 370 | ```js 371 | hotkeys('a', function(){ 372 | console.log(hotkeys.isPressed("a")); //=> true 373 | console.log(hotkeys.isPressed("A")); //=> true 374 | console.log(hotkeys.isPressed(65)); //=> true 375 | }); 376 | ``` 377 | 378 | ### getPressedKeyCodes 379 | 380 | 获取摁下绑定键的键值 `hotkeys.getPressedKeyCodes()` 381 | 382 | ```js 383 | hotkeys('command+ctrl+shift+a,f', function(){ 384 | console.log(hotkeys.getPressedKeyCodes()); //=> [17, 65] 或者 [70] 385 | }) 386 | ``` 387 | 388 | ### getPressedKeyString 389 | 390 | 获取所有注册代码的列表 391 | 392 | ```js 393 | hotkeys('command+ctrl+shift+a,f', function() { 394 | console.log(hotkeys.getPressedKeyString()); //=> ['⌘', '⌃', '⇧', 'A', 'F'] 395 | }) 396 | ``` 397 | 398 | 399 | ### getAllKeyCodes 400 | 401 | Get a list of all registration codes. 402 | 403 | ```js 404 | hotkeys('command+ctrl+shift+a,f', function() { 405 | console.log(hotkeys.getAllKeyCodes()); 406 | // [ 407 | // { scope: 'all', shortcut: 'command+ctrl+shift+a', mods: [91, 17, 16], keys: [91, 17, 16, 65] }, 408 | // { scope: 'all', shortcut: 'f', mods: [], keys: [42] } 409 | // ] 410 | }) 411 | ``` 412 | 413 | ### filter 414 | 415 | `INPUT` `SELECT` `TEXTAREA` 默认不处理。 416 | `hotkeys.filter` 返回 `true` 快捷键设置才会起作用,`false` 快捷键设置失效。 417 | 418 | ```javascript 419 | hotkeys.filter = function(event){ 420 | return true; 421 | } 422 | // 如何增加过滤可编辑标签
423 | // contentEditable老浏览器不支持滴 424 | hotkeys.filter = function(event) { 425 | var target = event.target || event.srcElement; 426 | var tagName = target.tagName; 427 | return !(target.isContentEditable || 428 | tagName == 'INPUT' || 429 | tagName == 'SELECT' || 430 | tagName == 'TEXTAREA'); 431 | } 432 | 433 | // 434 | hotkeys.filter = function(event){ 435 | var tagName = (event.target || event.srcElement).tagName; 436 | hotkeys.setScope(/^(INPUT|TEXTAREA|SELECT)$/.test(tagName) ? 'input' : 'other'); 437 | return true; 438 | } 439 | ``` 440 | 441 | ## 兼容模式 442 | 443 | ```js 444 | var k = hotkeys.noConflict(); 445 | k('a', function() { 446 | console.log("这里可以干一些事儿") 447 | }); 448 | 449 | hotkeys() 450 | // -->Uncaught TypeError: hotkeys is not a function(anonymous function) 451 | // @ VM2170:2InjectedScript._evaluateOn 452 | // @ VM2165:883InjectedScript._evaluateAndWrap 453 | // @ VM2165:816InjectedScript.evaluate @ VM2165:682 454 | ``` 455 | 456 | ## 开发 457 | 458 | 安装依赖,运行自重载构建,获取代码: 459 | 460 | ```shell 461 | $ git https://github.com/jaywcjlove/hotkeys.git 462 | $ cd hotkeys # 进入目录 463 | $ npm install # 或者使用 yarn install 安装依赖 464 | ``` 465 | 466 | 运行下面命令自动重载构建: 467 | 468 | ```shell 469 | $ npm run watch 470 | ``` 471 | 472 | 运行稳定环境 473 | 474 | ```shell 475 | $ npm run doc 476 | ``` 477 | 478 | 如果要贡献,请 fork `Hotkeys.js`, 并添加您的测试代码(在 test 目录中),并提交一个 PR。 479 | 480 | ```shell 481 | $ npm run test 482 | $ npm run test:watch # Development model 483 | ``` 484 | 485 | ## Contributors 486 | 487 | As always, thanks to our amazing contributors! 488 | 489 | 490 | 491 | 492 | 493 | Made with [github-action-contributors](https://github.com/jaywcjlove/github-action-contributors). 494 | 495 | 496 | ## License 497 | 498 | [MIT © Kenny Wong](./LICENSE) 499 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hotkeys 2 | 3 | 4 | 5 | [![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-048754?logo=buymeacoffee)](https://jaywcjlove.github.io/#/sponsor) 6 | [![](https://img.shields.io/npm/dm/hotkeys-js?logo=npm)](https://www.npmjs.com/package/hotkeys-js) 7 | [![](https://img.shields.io/github/stars/jaywcjlove/hotkeys-js.svg)](https://github.com/jaywcjlove/hotkeys/stargazers) 8 | ![no dependencies](http://jaywcjlove.github.io/sb/status/no-dependencies.svg) 9 | [![GitHub Actions CI](https://github.com/jaywcjlove/hotkeys-js/actions/workflows/ci.yml/badge.svg)](https://github.com/jaywcjlove/hotkeys-js/actions/workflows/ci.yml) 10 | [![Coverage Status](https://coveralls.io/repos/github/jaywcjlove/hotkeys/badge.svg?branch=master)](https://coveralls.io/github/jaywcjlove/hotkeys?branch=master) 11 | [![jaywcjlove/hotkeys-js](https://jaywcjlove.github.io/sb/lang/chinese.svg)](https://github.com/jaywcjlove/hotkeys-js/blob/master/README-zh.md) 12 | [![jaywcjlove/hotkeys-js](https://jaywcjlove.github.io/sb/ico/gitee.svg)](https://gitee.com/jaywcjlove/hotkeys) 13 | 14 | HotKeys.js is an input capture library with some very special features, it is easy to pick up and use, has a reasonable footprint ([~6kB](https://bundlephobia.com/result?p=hotkeys-js)) (gzipped: **`2.8kB`**), and has no dependencies. It should not interfere with any JavaScript libraries or frameworks. Official document [demo preview](https://jaywcjlove.github.io/hotkeys-js). [More examples](https://github.com/jaywcjlove/hotkeys-js/issues?q=label%3ADemo+). 15 | 16 | ```bash 17 | ╭┈┈╮ ╭┈┈╮ ╭┈┈╮ 18 | ┆ ├┈┈..┈┈┈┈┈.┆ └┈╮┆ ├┈┈..┈┈┈┈┈..┈┈.┈┈..┈┈┈┈┈. 19 | ┆ ┆┆ □ ┆┆ ┈┤┆ < ┆ -__┘┆ ┆ ┆┆__ ┈┈┤ 20 | ╰┈┈┴┈┈╯╰┈┈┈┈┈╯╰┈┈┈┈╯╰┈┈┴┈┈╯╰┈┈┈┈┈╯╰┈┈┈ ┆╰┈┈┈┈┈╯ 21 | ╰┈┈┈┈┈╯ 22 | ``` 23 | 24 | ## Usage 25 | 26 | You will need `Node.js` installed on your system. 27 | 28 | ```bash 29 | npm install hotkeys-js --save 30 | ``` 31 | 32 | ```js 33 | import hotkeys from 'hotkeys-js'; 34 | 35 | hotkeys('f5', function(event, handler){ 36 | // Prevent the default refresh event under WINDOWS system 37 | event.preventDefault() 38 | alert('you pressed F5!') 39 | }); 40 | ``` 41 | 42 | Or manually download and link **hotkeys.js** in your HTML, It can also be downloaded via [UNPKG](https://unpkg.com/hotkeys-js/dist/): 43 | 44 | CDN: [UNPKG](https://unpkg.com/hotkeys-js/dist/) | [jsDelivr](https://cdn.jsdelivr.net/npm/hotkeys-js@3.7.3/) | [Githack](https://raw.githack.com/jaywcjlove/hotkeys/master/dist/hotkeys.min.js) | [Statically](https://cdn.statically.io/gh/jaywcjlove/hotkeys/master/dist/hotkeys.min.js) | [bundle.run](https://bundle.run/hotkeys-js@3.7.3) 45 | 46 | ```html 47 | 48 | 63 | ``` 64 | 65 | ### Used in React 66 | 67 | [react-hotkeys](https://github.com/jaywcjlove/react-hotkeys) is the React component that listen to keydown and keyup keyboard events, defining and dispatching keyboard shortcuts. Detailed use method please see its documentation [react-hotkeys](https://github.com/jaywcjlove/react-hotkeys). 68 | 69 | [react-hotkeys-hook](https://github.com/JohannesKlauss/react-hotkeys-hook) - React hook for using keyboard shortcuts in components. Make sure that you have at least version 16.8 of react and react-dom installed, or otherwise hooks won't work for you. 70 | 71 | ## Browser Support 72 | 73 | Hotkeys.js has been tested and should work in. 74 | 75 | ```shell 76 | Internet Explorer 6+ 77 | Safari 78 | Firefox 79 | Chrome 80 | ``` 81 | 82 | ## Supported Keys 83 | 84 | HotKeys understands the following modifiers: `⇧`, `shift`, `option`, `⌥`, `alt`, `ctrl`, `control`, `command`, and `⌘`. 85 | 86 | The following special keys can be used for shortcuts: backspace, tab, clear, enter, return, esc, escape, space, up, down, left, right, home, end, pageup, pagedown, del, delete, f1 through f19, num_0 through num_9, num_multiply, num_add, num_enter, num_subtract, num_decimal, num_divide. 87 | 88 | `⌘` Command() 89 | `⌃` Control 90 | `⌥` Option(alt) 91 | `⇧` Shift 92 | `⇪` Caps Lock(Capital) 93 | ~~`fn` Does not support fn~~ 94 | `↩︎` return/Enter space 95 | 96 | ## Defining Shortcuts 97 | 98 | One global method is exposed, key which defines shortcuts when called directly. 99 | 100 | ```js 101 | hotkeys([keys:], [option:[string|object|function]], [callback:]) 102 | ``` 103 | 104 | 105 | ```js 106 | hotkeys('f5', function(event, handler) { 107 | // Prevent the default refresh event under WINDOWS system 108 | event.preventDefault(); 109 | alert('you pressed F5!'); 110 | }); 111 | 112 | // Returning false stops the event and prevents default browser events 113 | // Mac OS system defines `command + r` as a refresh shortcut 114 | hotkeys('ctrl+r, command+r', function() { 115 | alert('stopped reload!'); 116 | return false; 117 | }); 118 | 119 | // Single key 120 | hotkeys('a', function(event,handler){ 121 | //event.srcElement: input 122 | //event.target: input 123 | if(event.target === "input"){ 124 | alert('you pressed a!') 125 | } 126 | alert('you pressed a!') 127 | }); 128 | 129 | // Key Combination 130 | hotkeys('ctrl+a,ctrl+b,r,f', function (event, handler){ 131 | switch (handler.key) { 132 | case 'ctrl+a': alert('you pressed ctrl+a!'); 133 | break; 134 | case 'ctrl+b': alert('you pressed ctrl+b!'); 135 | break; 136 | case 'r': alert('you pressed r!'); 137 | break; 138 | case 'f': alert('you pressed f!'); 139 | break; 140 | default: alert(event); 141 | } 142 | }); 143 | 144 | hotkeys('ctrl+a+s', function() { 145 | alert('you pressed ctrl+a+s!'); 146 | }); 147 | 148 | // Using a scope 149 | hotkeys('*','wcj', function(event){ 150 | console.log('do something', event); 151 | }); 152 | ``` 153 | 154 | #### option 155 | 156 | - `scope`: Sets the scope in which the shortcut key is active 157 | - `element`: Specifies the DOM element to bind the event to 158 | - `keyup`: Whether to trigger the shortcut on key release 159 | - `keydown`: Whether to trigger the shortcut on key press 160 | - `splitKey`: Delimiter for key combinations (default is `+`) 161 | - `capture`: Whether to trigger the listener during the capture phase (before the event bubbles down) 162 | - `single`: Allows only one callback function (automatically unbinds previous one) 163 | 164 | ```js 165 | hotkeys('o, enter', { 166 | scope: 'wcj', 167 | element: document.getElementById('wrapper'), 168 | }, function() { 169 | console.log('do something else'); 170 | }); 171 | 172 | hotkeys('ctrl-+', { splitKey: '-' }, function(e) { 173 | console.log('you pressed ctrl and +'); 174 | }); 175 | 176 | hotkeys('+', { splitKey: '-' }, function(e){ 177 | console.log('you pressed +'); 178 | }) 179 | ``` 180 | 181 | **keyup** 182 | 183 | **key down** and **key up** both perform callback events. 184 | 185 | ```js 186 | hotkeys('ctrl+a,alt+a+s', {keyup: true}, function(event, handler) { 187 | if (event.type === 'keydown') { 188 | console.log('keydown:', event.type, handler, handler.key); 189 | } 190 | 191 | if (event.type === 'keyup') { 192 | console.log('keyup:', event.type, handler, handler.key); 193 | } 194 | }); 195 | ``` 196 | 197 | ## API REFERENCE 198 | 199 | Asterisk "*" 200 | 201 | Modifier key judgments 202 | 203 | ```js 204 | hotkeys('*', function() { 205 | if (hotkeys.shift) { 206 | console.log('shift is pressed!'); 207 | } 208 | 209 | if (hotkeys.ctrl) { 210 | console.log('ctrl is pressed!'); 211 | } 212 | 213 | if (hotkeys.alt) { 214 | console.log('alt is pressed!'); 215 | } 216 | 217 | if (hotkeys.option) { 218 | console.log('option is pressed!'); 219 | } 220 | 221 | if (hotkeys.control) { 222 | console.log('control is pressed!'); 223 | } 224 | 225 | if (hotkeys.cmd) { 226 | console.log('cmd is pressed!'); 227 | } 228 | 229 | if (hotkeys.command) { 230 | console.log('command is pressed!'); 231 | } 232 | }); 233 | ``` 234 | 235 | ### setScope 236 | 237 | Use the `hotkeys.setScope` method to set scope. There can only be one active scope besides 'all'. By default 'all' is always active. 238 | 239 | ```js 240 | // Define shortcuts with a scope 241 | hotkeys('ctrl+o, ctrl+alt+enter', 'issues', function() { 242 | console.log('do something'); 243 | }); 244 | hotkeys('o, enter', 'files', function() { 245 | console.log('do something else'); 246 | }); 247 | 248 | // Set the scope (only 'all' and 'issues' shortcuts will be honored) 249 | hotkeys.setScope('issues'); // default scope is 'all' 250 | ``` 251 | 252 | ### getScope 253 | 254 | Use the `hotkeys.getScope` method to get scope. 255 | 256 | ```js 257 | hotkeys.getScope(); 258 | ``` 259 | 260 | ### deleteScope 261 | 262 | Use the `hotkeys.deleteScope` method to delete a scope. This will also remove all associated hotkeys with it. 263 | 264 | ```js 265 | hotkeys.deleteScope('issues'); 266 | ``` 267 | You can use second argument, if need set new scope after deleting. 268 | 269 | ```js 270 | hotkeys.deleteScope('issues', 'newScopeName'); 271 | ``` 272 | 273 | ### unbind 274 | 275 | Similar to defining shortcuts, they can be unbound using `hotkeys.unbind`. 276 | 277 | ```js 278 | // unbind 'a' handler 279 | hotkeys.unbind('a'); 280 | 281 | // Unbind a hotkeys only for a single scope 282 | // If no scope is specified it defaults to the current scope (hotkeys.getScope()) 283 | hotkeys.unbind('o, enter', 'issues'); 284 | hotkeys.unbind('o, enter', 'files'); 285 | ``` 286 | 287 | Unbind events through functions. 288 | 289 | ```js 290 | function example() { 291 | hotkeys('a', example); 292 | hotkeys.unbind('a', example); 293 | 294 | hotkeys('a', 'issues', example); 295 | hotkeys.unbind('a', 'issues', example); 296 | } 297 | ``` 298 | 299 | To unbind everything. 300 | 301 | ```js 302 | hotkeys.unbind(); 303 | ``` 304 | 305 | ### isPressed 306 | 307 | For example, `hotkeys.isPressed(77)` is true if the `M` key is currently pressed. 308 | 309 | ```js 310 | hotkeys('a', function() { 311 | console.log(hotkeys.isPressed('a')); //=> true 312 | console.log(hotkeys.isPressed('A')); //=> true 313 | console.log(hotkeys.isPressed(65)); //=> true 314 | }); 315 | ``` 316 | 317 | ### trigger 318 | 319 | trigger shortcut key event 320 | 321 | ```js 322 | hotkeys.trigger('ctrl+o'); 323 | hotkeys.trigger('ctrl+o', 'scope2'); 324 | ``` 325 | 326 | ### getPressedKeyCodes 327 | 328 | Returns an array of key codes currently pressed. 329 | 330 | ```js 331 | hotkeys('command+ctrl+shift+a,f', function() { 332 | console.log(hotkeys.getPressedKeyCodes()); //=> [17, 65] or [70] 333 | }) 334 | ``` 335 | 336 | ### getPressedKeyString 337 | 338 | Returns an array of key codes currently pressed. 339 | 340 | ```js 341 | hotkeys('command+ctrl+shift+a,f', function() { 342 | console.log(hotkeys.getPressedKeyString()); //=> ['⌘', '⌃', '⇧', 'A', 'F'] 343 | }) 344 | ``` 345 | 346 | ### getAllKeyCodes 347 | 348 | Get a list of all registration codes. 349 | 350 | ```js 351 | hotkeys('command+ctrl+shift+a,f', function() { 352 | console.log(hotkeys.getAllKeyCodes()); 353 | // [ 354 | // { scope: 'all', shortcut: 'command+ctrl+shift+a', mods: [91, 17, 16], keys: [91, 17, 16, 65] }, 355 | // { scope: 'all', shortcut: 'f', mods: [], keys: [42] } 356 | // ] 357 | }) 358 | ``` 359 | 360 | ### filter 361 | 362 | By default hotkeys are not enabled for `INPUT` `SELECT` `TEXTAREA` elements. `Hotkeys.filter` to return to the `true` shortcut keys set to play a role, `false` shortcut keys set up failure. 363 | 364 | ```js 365 | hotkeys.filter = function(event){ 366 | return true; 367 | } 368 | //How to add the filter to edit labels.
369 | //"contentEditable" Older browsers that do not support drops 370 | hotkeys.filter = function(event) { 371 | var target = event.target || event.srcElement; 372 | var tagName = target.tagName; 373 | return !(target.isContentEditable || tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA'); 374 | } 375 | 376 | hotkeys.filter = function(event){ 377 | var tagName = (event.target || event.srcElement).tagName; 378 | hotkeys.setScope(/^(INPUT|TEXTAREA|SELECT)$/.test(tagName) ? 'input' : 'other'); 379 | return true; 380 | } 381 | ``` 382 | 383 | ### noConflict 384 | 385 | Relinquish HotKeys’s control of the `hotkeys` variable. 386 | 387 | ```js 388 | var k = hotkeys.noConflict(); 389 | k('a', function() { 390 | console.log("do something") 391 | }); 392 | 393 | hotkeys() 394 | // -->Uncaught TypeError: hotkeys is not a function(anonymous function) 395 | // @ VM2170:2InjectedScript._evaluateOn 396 | // @ VM2165:883InjectedScript._evaluateAndWrap 397 | // @ VM2165:816InjectedScript.evaluate @ VM2165:682 398 | ``` 399 | 400 | ## Development 401 | 402 | To develop, Install dependencies, Get the code: 403 | 404 | ```shell 405 | $ git https://github.com/jaywcjlove/hotkeys.git 406 | $ cd hotkeys # Into the directory 407 | $ npm install # or yarn install 408 | ``` 409 | 410 | To develop, run the self-reloading build: 411 | 412 | ```shell 413 | $ npm run watch 414 | ``` 415 | 416 | Run Document Website Environment. 417 | 418 | ```shell 419 | $ npm run doc 420 | ``` 421 | 422 | To contribute, please fork Hotkeys.js, add your patch and tests for it (in the `test/` folder) and submit a pull request. 423 | 424 | ```shell 425 | $ npm run test 426 | $ npm run test:watch # Development model 427 | ``` 428 | 429 | ## Contributors 430 | 431 | As always, thanks to our amazing contributors! 432 | 433 | 434 | 435 | 436 | 437 | Made with [github-action-contributors](https://github.com/jaywcjlove/github-action-contributors). 438 | 439 | ## License 440 | 441 | [MIT © Kenny Wong](./LICENSE) 442 | -------------------------------------------------------------------------------- /dist/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Explanation of Build Files 4 | --- 5 | 6 | | UMD | Size | CommonJS | Size | ES Module | Size | 7 | | ---- | ---- | ---- | ---- | ---- | ---- | 8 | | hotkeys.js | 8.37kb | hotkeys.common.js | 8.13kb | hotkeys.esm.js | 8.12kb | 9 | | hotkeys.min.js | 3.62kb (gzipped: 1.73kb) | hotkeys.common.min.js | (gzipped: 1.84kb) | - | - | 10 | 11 | - [UMD](https://github.com/umdjs/umd): UMD builds can be used directly in the browser via a `