diff --git a/README.md b/README.md
index a6f6dff0..04d2adf3 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,7 @@
- [`useHover` and `useHoverDirty`](./docs/useHover.md) — tracks mouse hover state of some element. [![][img-demo]](https://codesandbox.io/s/zpn583rvx)
- [`useIdle`](./docs/useIdle.md) — tracks whether user is being inactive.
- [`useKeyPress`](./docs/useKeyPress.md) — tracks whether a keyboard key—or set of keys—was pressed.
+ - [`useKeyPressEvent`](./docs/useKeyPressEvent.md) — call `onKeyDown` and `onKeyUp` callbacks, whe key pressed.
- [`useLocation`](./docs/useLocation.md) — tracks page navigation bar location state.
- [`useMedia`](./docs/useMedia.md) — tracks state of a CSS media query. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/sensors-usemedia--demo)
- [`useMediaDevices`](./docs/useMediaDevices.md) — tracks state of connected hardware devices.
diff --git a/docs/useKeyPressEvent.md b/docs/useKeyPressEvent.md
new file mode 100644
index 00000000..930f3174
--- /dev/null
+++ b/docs/useKeyPressEvent.md
@@ -0,0 +1,50 @@
+# `useKeyPressEvent`
+
+React UI sensor hook that detects when the user is pressing a specific
+key on their keyboard and fires a specified keyup and/or keydown effect. If
+you only need to retrieve the state, see [useKeyPress](#).
+
+Complex bindings like detecting when multiple keys are held down at the same
+time or requiring them to be held down in a specified order are also available
+via [KeyboardJS key combos](https://github.com/RobertWHurst/KeyboardJS).
+Check its documentation for further details on how to make combo strings.
+
+The first argument is the key(s) to watch. If only a second argument
+(a function) is passed, it will be used in the keydown event. On the other hand,
+if a second and third argument are passed, the second will be used in the keyup
+event and the third in the keydown event. Essentially, keydown takes precedence.
+
+## Usage
+
+```jsx
+import React, { useState } from React;
+import { useKeyPressEvent } from "react-use";
+
+const Demo = () => {
+ const [count, setCount] = useState(0);
+
+ const increment = () => setCount(count => ++count);
+ const decrement = () => setCount(count => --count);
+ const reset = () => setCount(count => 0);
+
+ useKeyPressEvent(']', increment, increment);
+ useKeyPressEvent('[', decrement, decrement);
+ useKeyPressEvent('r', reset);
+
+ return (
+
+
+ Try pressing [, ], and r to
+ see the count incremented and decremented.
+
Count: {count}
+
+ );
+};
+```
+
+## Reference
+
+```js
+useKeyPressEvent('', onKeydown);
+useKeyPressEvent('', onKeyup, onKeydown);
+```
diff --git a/src/__stories__/useKeyPressEvent.story.tsx b/src/__stories__/useKeyPressEvent.story.tsx
new file mode 100644
index 00000000..045a1464
--- /dev/null
+++ b/src/__stories__/useKeyPressEvent.story.tsx
@@ -0,0 +1,30 @@
+import { storiesOf } from "@storybook/react";
+import * as React from "react";
+import { useKeyPressEvent } from "..";
+import ShowDocs from "../util/ShowDocs";
+
+const Demo = () => {
+ const [count, setCount] = React.useState(0);
+
+ const increment = () => setCount(count => ++count);
+ const decrement = () => setCount(count => --count);
+ const reset = () => setCount(count => 0);
+
+ useKeyPressEvent(']', increment, increment);
+ useKeyPressEvent('[', decrement, decrement);
+ useKeyPressEvent('r', reset);
+
+ return (
+
+
+
+ Try pressing [, ], and r to
+ see the count incremented and decremented.
+
Count: {count}
+
+ );
+};
+
+storiesOf("Sensors/useKeyPressEvent", module)
+ .add("Docs", () => )
+ .add("Demo", () => );
diff --git a/src/index.ts b/src/index.ts
index 7e5dd099..343a4533 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -15,6 +15,7 @@ import useHover from './useHover';
import useHoverDirty from './useHoverDirty';
import useIdle from './useIdle';
import useKeyPress from './useKeyPress';
+import useKeyPressEvent from './useKeyPressEvent';
import useLifecycles from './useLifecycles';
import useList from './useList';
import useLocalStorage from './useLocalStorage';
@@ -66,6 +67,7 @@ export {
useHoverDirty,
useIdle,
useKeyPress,
+ useKeyPressEvent,
useLifecycles,
useList,
useLocalStorage,
diff --git a/src/useKeyPressEvent.ts b/src/useKeyPressEvent.ts
new file mode 100644
index 00000000..44d01692
--- /dev/null
+++ b/src/useKeyPressEvent.ts
@@ -0,0 +1,35 @@
+import * as React from 'react';
+const { useEffect } = React;
+import useKeyPress from './useKeyPress';
+
+type KeyPressCallback = ((targetKey: string) => void) | undefined | null;
+
+const useKeyPressEvent = (
+ targetKey: string,
+ onKeyup: KeyPressCallback = undefined,
+ onKeydown: KeyPressCallback = undefined
+) => {
+ const useKeyboardJS: boolean = targetKey.length > 1;
+ const pressedKeys: boolean = useKeyPress(targetKey, {
+ useKeyboardJS,
+ });
+
+ if (onKeydown === undefined) {
+ onKeydown = onKeyup;
+ onKeyup = null;
+ }
+
+ useEffect(
+ () => {
+ if (!pressedKeys) {
+ if (onKeyup) onKeyup(targetKey);
+ return;
+ }
+
+ if (onKeydown) onKeydown(targetKey);
+ },
+ [pressedKeys]
+ );
+};
+
+export default useKeyPressEvent;
diff --git a/yarn.lock b/yarn.lock
index ea02d980..55376c7d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10862,7 +10862,7 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-typescript@3.3.3333:
+typescript@^3.3.3333:
version "3.3.3333"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3333.tgz#171b2c5af66c59e9431199117a3bcadc66fdcfd6"
integrity sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==