├── .eslintignore
├── .github
└── FUNDING.yml
├── .gitignore
├── README.md
├── misc
└── keypressLogo.png
├── packages
├── demo
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierrc.json
│ ├── README.md
│ ├── package.json
│ ├── public
│ │ ├── emptyKey.png
│ │ ├── index.html
│ │ └── keypressLogo.png
│ ├── src
│ │ ├── App.vue
│ │ ├── components
│ │ │ ├── KeyBackground.vue
│ │ │ └── KeypressHandler.vue
│ │ ├── main.ts
│ │ └── shims-vue.d.ts
│ ├── tsconfig.json
│ ├── vue.config.js
│ └── yarn.lock
└── vue3-keypress
│ ├── .eslintrc.js
│ ├── .npmignore
│ ├── .prettierrc.json
│ ├── @types
│ └── index.ts
│ ├── package.json
│ ├── src
│ ├── key_codes.ts
│ └── vue3_keypress.ts
│ ├── tsconfig.json
│ └── yarn.lock
└── vetur.config.js
/.eslintignore:
--------------------------------------------------------------------------------
1 | lib/**
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # Enables "Sponsor" button on project
2 |
3 | github: lupas
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | lib
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |

2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | # ⚠️ Breaking Changes with V4 ⚠️
11 |
12 | Version 4 introduced breaking changes by making use of the Vue 3 composition API and dropping the component-based approach.
13 | Follow the guide below to setup the module following the new approach.
14 |
15 | # Vue Keypress
16 |
17 | Want to capture _keydown_, _keypress_ and _keyup_ and events globally in Vue? Nothing easier than that.
18 |
19 | The Vue Keypress Component let's you do just that.
20 |
21 | Just add the component to the view/component that should start a global keypress handler. When the component gets destroyed, the global event handler also gets removed.
22 |
23 | # ‼️ Using Vue 2?
24 |
25 | This package only supports Vue 3.
26 |
27 | For Vue 2 support, visit the [lupas/vue-keypress](https://github.com/lupas/vue-keypress) package repository.
28 |
29 | # How to install?
30 |
31 | ```bsh
32 | yarn add vue3-keypress
33 | // or
34 | npm i vue3-keypress
35 | ```
36 |
37 | # How to use in your project?
38 |
39 | # Simple Example
40 |
41 | ```vue
42 |
62 | ```
63 |
64 | # Full Example
65 |
66 | ```vue
67 |
117 | ```
118 |
119 | # Config
120 |
121 | | Variable | Type | Default | Possible Values | Description |
122 | | ---------- | ------------ | ------- | ------------------------------ | --------------------------------------------------------------------------------- |
123 | | keyEvent | String | 'keyup' | _keydown_, _keypress_, _keyup_ | |
124 | | keyBinds | KeyBind[] | [] | see below | Object containing infos about which keys are expected to be pressed. |
125 | | isActive | Ref(Boolean) | false | true / false | Setups up a listener that activates/deactivates the keypress listener. |
126 | | onWrongKey | Function | null | | Callback that is triggered every time a key is pressed that is not in "keyBinds". |
127 | | onAnyKey | Function | null | | Callback that is triggered every time a key is pressed. |
128 |
129 | ## Key Binds
130 |
131 | | Variable | Type | Default | Possible Values | Description |
132 | | -------------- | --------------- | ------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------- |
133 | | keyCode | Number / String | null | [KeyCode as integer](https://keycode.info/) or a [mapped string](https://github.com/lupas/vue3-keypress/blob/master/packages/vue3-keypress/src/key_codes.ts) | Key that should trigger the event. If _null_, any key will trigger event. |
134 | | modifiers | Array | [] | ['_ctrlKey_', '_shiftKey_', '_altKey_', '_metaKey_'] | Keys that needs to be pressed down before the actual key (key Code), e.g. Ctrl+A. |
135 | | preventDefault | Boolean | true | _true_,_false_ | Prevent the default action of the event |
136 | | success | Function | null | | Callback that is triggered when the correct key is pressed. |
137 |
138 | The return payload of the callbacks is like so:
139 |
140 | ```js
141 | {
142 | event: Object, // the official event object
143 | expectedEvent: Object, // your defined props.
144 | message: String // A declarative message on error/success.
145 | }
146 | ```
147 |
--------------------------------------------------------------------------------
/misc/keypressLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lupas/vue3-keypress/7a4bd680493e3d2ffaa72e1d42d2ef8a66c54d9b/misc/keypressLogo.png
--------------------------------------------------------------------------------
/packages/demo/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | browser: true,
5 | node: true
6 | },
7 | extends: [
8 | 'plugin:vue/vue3-essential',
9 | 'eslint:recommended',
10 | '@vue/typescript/recommended',
11 | 'prettier',
12 | 'prettier/vue',
13 | 'plugin:prettier/recommended'
14 | ],
15 | // add your custom rules here
16 | rules: {
17 | 'no-console': 'off',
18 | 'no-unused-vars': 'warn',
19 | 'object-shorthand': 'warn',
20 | '@typescript-eslint/member-delimiter-style': 'off'
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/packages/demo/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/packages/demo/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "arrowParens": "always",
4 | "singleQuote": true
5 | }
6 |
--------------------------------------------------------------------------------
/packages/demo/README.md:
--------------------------------------------------------------------------------
1 | # demo2
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Lints and fixes files
19 | ```
20 | npm run lint
21 | ```
22 |
23 | ### Customize configuration
24 | See [Configuration Reference](https://cli.vuejs.org/config/).
25 |
--------------------------------------------------------------------------------
/packages/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "keypressdemo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "vue": "^3.0.0",
12 | "vue3-keypress": "^4.0.0-beta3"
13 | },
14 | "devDependencies": {
15 | "@typescript-eslint/eslint-plugin": "^2.33.0",
16 | "@typescript-eslint/parser": "^2.33.0",
17 | "@vue/cli-plugin-eslint": "~4.5.0",
18 | "@vue/cli-plugin-typescript": "~4.5.0",
19 | "@vue/cli-service": "~4.5.0",
20 | "@vue/compiler-sfc": "^3.0.0",
21 | "@vue/eslint-config-prettier": "^6.0.0",
22 | "@vue/eslint-config-typescript": "^5.0.2",
23 | "eslint": "^6.7.2",
24 | "eslint-plugin-prettier": "^3.1.3",
25 | "eslint-plugin-vue": "^7.0.0-0",
26 | "prettier": "^1.19.1",
27 | "typescript": "~3.9.3"
28 | },
29 | "browserslist": [
30 | "> 1%",
31 | "last 2 versions",
32 | "not dead"
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/packages/demo/public/emptyKey.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lupas/vue3-keypress/7a4bd680493e3d2ffaa72e1d42d2ef8a66c54d9b/packages/demo/public/emptyKey.png
--------------------------------------------------------------------------------
/packages/demo/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/packages/demo/public/keypressLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lupas/vue3-keypress/7a4bd680493e3d2ffaa72e1d42d2ef8a66c54d9b/packages/demo/public/keypressLogo.png
--------------------------------------------------------------------------------
/packages/demo/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
17 |
18 |
30 |
--------------------------------------------------------------------------------
/packages/demo/src/components/KeyBackground.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ pressedKeyCode }}
5 |
6 |
7 |
8 |
9 |
28 |
29 |
47 |
--------------------------------------------------------------------------------
/packages/demo/src/components/KeypressHandler.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{ isSuccess ? 'Success!' : 'Wrong Key!' }}
6 |
9 |
10 |
11 |
12 |
78 |
--------------------------------------------------------------------------------
/packages/demo/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 |
4 | createApp(App).mount('#app')
5 |
--------------------------------------------------------------------------------
/packages/demo/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | declare module '*.vue' {
3 | import type { DefineComponent } from 'vue'
4 | const component: DefineComponent<{}, {}, any>
5 | export default component
6 | }
7 |
--------------------------------------------------------------------------------
/packages/demo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "esnext",
5 | "strict": true,
6 | "jsx": "preserve",
7 | "importHelpers": true,
8 | "moduleResolution": "node",
9 | "skipLibCheck": true,
10 | "esModuleInterop": true,
11 | "allowSyntheticDefaultImports": true,
12 | "sourceMap": true,
13 | "baseUrl": ".",
14 | "types": ["webpack-env"],
15 | "paths": {
16 | "@/*": ["src/*"]
17 | },
18 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
19 | },
20 | "include": [
21 | "src/**/*.ts",
22 | "src/**/*.tsx",
23 | "src/**/*.vue",
24 | "tests/**/*.ts",
25 | "tests/**/*.tsx"
26 | ],
27 | "exclude": ["node_modules", "lib"]
28 | }
29 |
--------------------------------------------------------------------------------
/packages/demo/vue.config.js:
--------------------------------------------------------------------------------
1 | // vue.config.js
2 | module.exports = {
3 | // ...
4 | configureWebpack: {
5 | resolve: { symlinks: false }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/vue3-keypress/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | browser: true,
5 | node: true,
6 | },
7 | parserOptions: {
8 | parser: 'babel-eslint',
9 | },
10 | extends: [
11 | 'plugin:vue/vue3-essential',
12 | 'eslint:recommended',
13 | '@vue/typescript/recommended',
14 | 'prettier',
15 | 'prettier/vue',
16 | 'plugin:prettier/recommended',
17 | ],
18 | // add your custom rules here
19 | rules: {
20 | 'no-console': 'off',
21 | 'no-unused-vars': 'warn',
22 | 'object-shorthand': 'warn',
23 | },
24 | }
25 |
--------------------------------------------------------------------------------
/packages/vue3-keypress/.npmignore:
--------------------------------------------------------------------------------
1 | build
2 | node_modules
3 | src
4 | .eslintrc.js
5 | .prettierrc.json
6 | tsconfig.json
7 | yarn.lock
--------------------------------------------------------------------------------
/packages/vue3-keypress/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "arrowParens": "always",
4 | "singleQuote": true
5 | }
6 |
--------------------------------------------------------------------------------
/packages/vue3-keypress/@types/index.ts:
--------------------------------------------------------------------------------
1 | interface KeyBind {
2 | keyCode: string
3 | modifiers?: ['altKey' | 'metaKey' | 'ctrlKey' | 'shiftKey']
4 | preventDefault: boolean
5 | success: { (SuccessResult): void }
6 | }
7 |
8 | interface KeypressOptions {
9 | keyEvent: 'keydown' | 'keypress' | 'keyup'
10 | keyBinds: KeyBind[]
11 | isActive?: any // TODO
12 | onAnyKey?: { (SuccessResult): void }
13 | onWrongKey?: { (SuccessResult): void }
14 | }
15 |
16 | interface KeypressResult {
17 | event: KeypressResult
18 | keyEvent: string
19 | }
20 |
21 | interface SuccessResult extends KeypressResult {
22 | keyCode: string
23 | keyEvent: string
24 | modifiers: ['altKey' | 'metaKey' | 'ctrlKey' | 'shiftKey']
25 | preventDefault: boolean
26 | }
27 |
--------------------------------------------------------------------------------
/packages/vue3-keypress/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue3-keypress",
3 | "version": "4.0.1",
4 | "description": "Global keypress event handler component for Vue.js 3 applications.",
5 | "author": "Pascal Luther",
6 | "license": "MIT",
7 | "homepage": "https://github.com/lupas/vue-keypress",
8 | "repository": "https://github.com/lupas/vue-keypress",
9 | "keywords": [
10 | "vue, keypress, keydown, keyup"
11 | ],
12 | "publishConfig": {
13 | "access": "public"
14 | },
15 | "scripts": {
16 | "build": "tsc",
17 | "publishToNpm": "npm run build && npm publish",
18 | "demo": "cd demo && yarn dev"
19 | },
20 | "main": "lib/src/vue3_keypress.js",
21 | "devDependencies": {
22 | "@typescript-eslint/eslint-plugin": "^4.13.0",
23 | "@typescript-eslint/parser": "^4.13.0",
24 | "@vue/eslint-config-typescript": "^7.0.0",
25 | "babel-eslint": "^10.1.0",
26 | "eslint": "^7.16.0",
27 | "eslint-config-prettier": "^7.1.0",
28 | "eslint-loader": "^4.0.2",
29 | "eslint-plugin-prettier": "^3.3.0",
30 | "eslint-plugin-vue": "^7.4.0",
31 | "prettier": "^2.2.1",
32 | "vue": "^3.0.5",
33 | "@vue/cli-plugin-typescript": "^4.5.10",
34 | "typescript": "^4.1.3"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/packages/vue3-keypress/src/key_codes.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | backspace: 8,
3 | tab: 9,
4 | enter: 13,
5 | shift: 16,
6 | ctrl: 17,
7 | alt: 18,
8 | 'pause/break': 19,
9 | 'caps lock': 20,
10 | esc: 27,
11 | space: 32,
12 | 'page up': 33,
13 | 'page down': 34,
14 | end: 35,
15 | home: 36,
16 | left: 37,
17 | up: 38,
18 | right: 39,
19 | down: 40,
20 | insert: 45,
21 | delete: 46,
22 | command: 91,
23 | 'left command': 91,
24 | 'right command': 93,
25 | 'numpad *': 106,
26 | 'numpad +': 107,
27 | 'numpad -': 109,
28 | 'numpad .': 110,
29 | 'numpad /': 111,
30 | 'num lock': 144,
31 | 'scroll lock': 145,
32 | 'my computer': 182,
33 | 'my calculator': 183,
34 | ';': 186,
35 | '=': 187,
36 | ',': 188,
37 | '-': 189,
38 | '.': 190,
39 | '/': 191,
40 | '`': 192,
41 | '[': 219,
42 | '\\': 220,
43 | ']': 221,
44 | "'": 222,
45 | }
46 |
--------------------------------------------------------------------------------
/packages/vue3-keypress/src/vue3_keypress.ts:
--------------------------------------------------------------------------------
1 | import { watch, onMounted, onUnmounted } from 'vue'
2 | import keyCodes from './key_codes'
3 |
4 | const supportedModifiers = ['altKey', 'metaKey', 'ctrlKey', 'shiftKey']
5 |
6 | export const useKeypress = ({
7 | keyEvent,
8 | keyBinds,
9 | onAnyKey,
10 | onWrongKey,
11 | isActive: isListenerActiveRef,
12 | }: KeypressOptions) => {
13 | let eventListener = null
14 |
15 | for (const keyBind of keyBinds) {
16 | keyBind.keyCode = keyCodes[keyBind.keyCode] || keyBind.keyCode
17 | }
18 |
19 | const requiredModifiersPressed = (event, modifiers) => {
20 | return supportedModifiers.every(
21 | (modifier) => event[modifier] == (modifiers.indexOf(modifier) !== -1)
22 | )
23 | }
24 |
25 | const anyModifiersPress = (event, modifiers) => {
26 | return supportedModifiers.some((modifier) => !!event[modifier])
27 | }
28 |
29 | const eventHandler = () => {
30 | return (event) => {
31 | const callbackData = (eventData = {}) => ({
32 | event,
33 | keyEvent,
34 | ...eventData,
35 | })
36 |
37 | if (typeof onAnyKey == 'function')
38 | onAnyKey(callbackData(event) as KeypressResult)
39 |
40 | for (const {
41 | keyCode,
42 | modifiers,
43 | success,
44 | preventDefault = true,
45 | } of keyBinds) {
46 | // Check if the correct keys have been clicked:
47 | if (keyCode !== event.keyCode) continue
48 |
49 | if (modifiers && modifiers.length > 0) {
50 | if (!requiredModifiersPressed(event, modifiers)) continue
51 | } else {
52 | if (anyModifiersPress(event, modifiers)) continue
53 | }
54 |
55 | if (preventDefault) event.preventDefault()
56 |
57 | // SUCCESS -> the correct key was pressed if we got to this point
58 | success(
59 | callbackData({
60 | keyCode,
61 | modifiers,
62 | preventDefault,
63 | event,
64 | } as SuccessResult)
65 | )
66 |
67 | return !preventDefault
68 | }
69 | if (typeof onWrongKey == 'function')
70 | onWrongKey(callbackData(event) as KeypressResult)
71 | return null
72 | }
73 | }
74 |
75 | const addListener = () => {
76 | if (!eventListener) eventListener = eventHandler()
77 | window.addEventListener(keyEvent, eventListener)
78 | }
79 |
80 | const removeListener = () => {
81 | if (!eventListener) return
82 | window.removeEventListener(keyEvent, eventListener)
83 | }
84 |
85 | if (isListenerActiveRef) {
86 | if (isListenerActiveRef.value) addListener()
87 | watch(isListenerActiveRef, (active) => {
88 | active ? addListener() : removeListener()
89 | })
90 | } else {
91 | onMounted(() => addListener())
92 | }
93 |
94 | onUnmounted(() => removeListener())
95 | }
96 |
--------------------------------------------------------------------------------
/packages/vue3-keypress/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
4 | "moduleResolution": "node",
5 | "target": "esnext",
6 | "module": "esnext",
7 | "noImplicitReturns": true,
8 | "outDir": "lib",
9 | "sourceMap": true,
10 | "skipLibCheck": true,
11 | "declaration": true
12 | },
13 | "compileOnSave": false,
14 | "include": [
15 | "src/**/*.ts",
16 | "src/**/*.tsx",
17 | "src/**/*.vue",
18 | "@types/*.ts",
19 | "@types/**/*.ts"
20 | ],
21 | "exclude": ["node_modules", "lib"]
22 | }
23 |
--------------------------------------------------------------------------------
/vetur.config.js:
--------------------------------------------------------------------------------
1 | // vetur.config.js
2 | /** @type {import('vls').VeturConfig} */
3 | module.exports = {
4 | settings: {},
5 | // support monorepos
6 | projects: ["./packages/demo", "./packages/vue3-keypress"],
7 | };
8 |
--------------------------------------------------------------------------------