Add comprehensive reference documentation for: - Vitest: environments, projects/workspaces, type testing, vi utilities - Pinia: HMR, Nuxt integration, SSR setup - Vue: built-in components (Transition, Teleport, Suspense, KeepAlive) and advanced directives
246 lines
6.0 KiB
Markdown
246 lines
6.0 KiB
Markdown
---
|
|
category: Sensors
|
|
---
|
|
|
|
# useMagicKeys
|
|
|
|
Reactive keys pressed state, with magical keys combination support.
|
|
|
|
## Usage
|
|
|
|
```ts
|
|
import { useMagicKeys } from '@vueuse/core'
|
|
|
|
const { shift, space, a /* keys you want to monitor */ } = useMagicKeys()
|
|
|
|
watch(space, (v) => {
|
|
if (v)
|
|
console.log('space has been pressed')
|
|
})
|
|
|
|
watchEffect(() => {
|
|
if (shift.value && a.value)
|
|
console.log('Shift + A have been pressed')
|
|
})
|
|
```
|
|
|
|
::: tip NOTE
|
|
If you're using TypeScript with `noUncheckedIndexedAccess` enabled in your `tsconfig.json` (or using Nuxt which enables it by default), the destructured keys will have the type `ComputedRef<boolean> | undefined`.
|
|
|
|
The `noUncheckedIndexedAccess` TypeScript option adds `undefined` to any un-declared field accessed via index signatures. Since `useMagicKeys()` uses an index signature to allow accessing any key dynamically, TypeScript will treat destructured properties as potentially undefined for type safety.
|
|
|
|
You'll need to use optional chaining or wrap with a getter function:
|
|
|
|
```ts
|
|
const { shift, space, a } = useMagicKeys()
|
|
|
|
watch(
|
|
() => space?.value,
|
|
(v) => {
|
|
if (v)
|
|
console.log('space has been pressed')
|
|
},
|
|
)
|
|
|
|
watchEffect(() => {
|
|
if (shift?.value && a?.value)
|
|
console.log('Shift + A have been pressed')
|
|
})
|
|
```
|
|
|
|
Check the [TypeScript documentation](https://www.typescriptlang.org/tsconfig/#noUncheckedIndexedAccess) for more details about `noUncheckedIndexedAccess`.
|
|
|
|
:::
|
|
|
|
Check out [all the possible keycodes](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values).
|
|
|
|
### Combinations
|
|
|
|
You can magically use combinations (shortcuts/hotkeys) by connecting keys with `+` or `_`.
|
|
|
|
```ts
|
|
import { useMagicKeys } from '@vueuse/core'
|
|
|
|
const keys = useMagicKeys()
|
|
const shiftCtrlA = keys['Shift+Ctrl+A']
|
|
|
|
watch(shiftCtrlA, (v) => {
|
|
if (v)
|
|
console.log('Shift + Ctrl + A have been pressed')
|
|
})
|
|
```
|
|
|
|
```ts
|
|
import { useMagicKeys } from '@vueuse/core'
|
|
|
|
const { Ctrl_A_B, space, alt_s /* ... */ } = useMagicKeys()
|
|
|
|
watch(Ctrl_A_B, (v) => {
|
|
if (v)
|
|
console.log('Control+A+B have been pressed')
|
|
})
|
|
```
|
|
|
|
You can also use `whenever` function to make it shorter
|
|
|
|
```ts
|
|
import { useMagicKeys, whenever } from '@vueuse/core'
|
|
|
|
const keys = useMagicKeys()
|
|
|
|
whenever(keys.shift_space, () => {
|
|
console.log('Shift+Space have been pressed')
|
|
})
|
|
```
|
|
|
|
### Current Pressed keys
|
|
|
|
A special property `current` is provided to representing all the keys been pressed currently.
|
|
|
|
```ts
|
|
import { useMagicKeys, whenever } from '@vueuse/core'
|
|
|
|
const { current } = useMagicKeys()
|
|
|
|
console.log(current) // Set { 'control', 'a' }
|
|
|
|
whenever(
|
|
() => current.has('a') && !current.has('b'),
|
|
() => console.log('A is pressed but not B'),
|
|
)
|
|
```
|
|
|
|
### Key Aliasing
|
|
|
|
```ts
|
|
import { useMagicKeys, whenever } from '@vueuse/core'
|
|
|
|
const { shift_cool } = useMagicKeys({
|
|
aliasMap: {
|
|
cool: 'space',
|
|
},
|
|
})
|
|
|
|
whenever(shift_cool, () => console.log('Shift + Space have been pressed'))
|
|
```
|
|
|
|
By default, we have some [preconfigured alias for common practices](https://github.com/vueuse/vueuse/blob/main/packages/core/useMagicKeys/aliasMap.ts).
|
|
|
|
### Conditionally Disable
|
|
|
|
You might have some `<input />` elements in your apps, and you don't want to trigger the magic keys handling when users focused on those inputs. There is an example of using `useActiveElement` and `logicAnd` to do that.
|
|
|
|
```ts
|
|
import { useActiveElement, useMagicKeys, whenever } from '@vueuse/core'
|
|
import { logicAnd } from '@vueuse/math'
|
|
|
|
const activeElement = useActiveElement()
|
|
const notUsingInput = computed(() =>
|
|
activeElement.value?.tagName !== 'INPUT'
|
|
&& activeElement.value?.tagName !== 'TEXTAREA',)
|
|
|
|
const { tab } = useMagicKeys()
|
|
|
|
whenever(logicAnd(tab, notUsingInput), () => {
|
|
console.log('Tab has been pressed outside of inputs!')
|
|
})
|
|
```
|
|
|
|
### Custom Event Handler
|
|
|
|
```ts
|
|
import { useMagicKeys, whenever } from '@vueuse/core'
|
|
|
|
const { ctrl_s } = useMagicKeys({
|
|
passive: false,
|
|
onEventFired(e) {
|
|
if (e.ctrlKey && e.key === 's' && e.type === 'keydown')
|
|
e.preventDefault()
|
|
},
|
|
})
|
|
|
|
whenever(ctrl_s, () => console.log('Ctrl+S have been pressed'))
|
|
```
|
|
|
|
> ⚠️ This usage is NOT recommended, please use with caution.
|
|
|
|
### Reactive Mode
|
|
|
|
By default, the values of `useMagicKeys()` are `Ref<boolean>`. If you want to use the object in the template, you can set it to reactive mode.
|
|
|
|
```ts
|
|
import { useMagicKeys } from '@vueuse/core'
|
|
// ---cut---
|
|
const keys = useMagicKeys({ reactive: true })
|
|
```
|
|
|
|
```vue
|
|
<template>
|
|
<div v-if="keys.shift">
|
|
You are holding the Shift key!
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
## Type Declarations
|
|
|
|
```ts
|
|
export interface UseMagicKeysOptions<Reactive extends boolean> {
|
|
/**
|
|
* Returns a reactive object instead of an object of refs
|
|
*
|
|
* @default false
|
|
*/
|
|
reactive?: Reactive
|
|
/**
|
|
* Target for listening events
|
|
*
|
|
* @default window
|
|
*/
|
|
target?: MaybeRefOrGetter<EventTarget>
|
|
/**
|
|
* Alias map for keys, all the keys should be lowercase
|
|
* { target: keycode }
|
|
*
|
|
* @example { ctrl: "control" }
|
|
* @default <predefined-map>
|
|
*/
|
|
aliasMap?: Record<string, string>
|
|
/**
|
|
* Register passive listener
|
|
*
|
|
* @default true
|
|
*/
|
|
passive?: boolean
|
|
/**
|
|
* Custom event handler for keydown/keyup event.
|
|
* Useful when you want to apply custom logic.
|
|
*
|
|
* When using `e.preventDefault()`, you will need to pass `passive: false` to useMagicKeys().
|
|
*/
|
|
onEventFired?: (e: KeyboardEvent) => void | boolean
|
|
}
|
|
export interface MagicKeysInternal {
|
|
/**
|
|
* A Set of currently pressed keys,
|
|
* Stores raw keyCodes.
|
|
*
|
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
|
|
*/
|
|
current: Set<string>
|
|
}
|
|
export type UseMagicKeysReturn<Reactive extends boolean> = Readonly<
|
|
Record<string, Reactive extends true ? boolean : ComputedRef<boolean>> &
|
|
MagicKeysInternal
|
|
>
|
|
/**
|
|
* Reactive keys pressed state, with magical keys combination support.
|
|
*
|
|
* @see https://vueuse.org/useMagicKeys
|
|
*/
|
|
export declare function useMagicKeys<T extends boolean = false>(
|
|
options?: UseMagicKeysOptions<T>,
|
|
): UseMagicKeysReturn<T>
|
|
export { DefaultMagicKeysAliasMap } from "./aliasMap"
|
|
```
|