diff --git a/package.json b/package.json
index 637ea0f23..3108a4815 100644
--- a/package.json
+++ b/package.json
@@ -48,6 +48,7 @@
"cli-truncate": "^1.1.0",
"is-ci": "^2.0.0",
"jsdom": "^15.1.1",
+ "keycode": "^2.2.0",
"lodash.throttle": "^4.1.1",
"log-update": "^3.0.0",
"prop-types": "^15.6.2",
diff --git a/src/components/App.js b/src/components/App.js
index 748c7572f..7d7e779f2 100644
--- a/src/components/App.js
+++ b/src/components/App.js
@@ -2,10 +2,82 @@ import readline from 'readline';
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import cliCursor from 'cli-cursor';
+import {default as keycode} from 'keycode';
import AppContext from './AppContext';
import StdinContext from './StdinContext';
import StdoutContext from './StdoutContext';
+class DOMKeypressDispatcher extends PureComponent {
+ static propTypes = {
+ stdin: PropTypes.object.isRequired,
+ setRawMode: PropTypes.func.isRequired,
+ document: PropTypes.any,
+ window: PropTypes.any
+ };
+
+ componentDidMount() {
+ if (this.props.document) {
+ const {stdin, setRawMode} = this.props;
+ setRawMode(true);
+ stdin.on('keypress', this.dispatchInput);
+ }
+ }
+
+ componentWillUnmount() {
+ if (this.props.document) {
+ const {stdin, setRawMode} = this.props;
+ stdin.removeListener('keypress', this.dispatchInput);
+ setRawMode(false);
+ }
+ }
+
+ render() {
+ return (null);
+ }
+
+ dispatchInput = (str, key) => {
+ const code = keycode(key.name);
+ const downEvent = new this.props.window.KeyboardEvent('keydown', {
+ key: key.name,
+ charCode: code,
+ ctrlKey: key.ctrl,
+ shiftKey: key.shift,
+ keyCode: code,
+ which: code,
+ bubbles: true,
+ repeat: false,
+ location: 0,
+ isComposing: false
+ });
+ this.props.document.activeElement.dispatchEvent(downEvent);
+ const pressEvent = new this.props.window.KeyboardEvent('keypress', {
+ key: key.name,
+ charCode: code,
+ ctrlKey: key.ctrl,
+ shiftKey: key.shift,
+ keyCode: code,
+ which: code,
+ bubbles: true,
+ repeat: false,
+ location: 0,
+ isComposing: false
+ });
+ this.props.document.activeElement.dispatchEvent(pressEvent);
+ const upEvent = new this.props.window.KeyboardEvent('keyup', {
+ key: key.name,
+ charCode: code,
+ ctrlKey: key.ctrl,
+ shiftKey: key.shift,
+ keyCode: code,
+ which: code,
+ bubbles: true,
+ repeat: false,
+ location: 0,
+ isComposing: false
+ });
+ this.props.document.activeElement.dispatchEvent(upEvent);
+ }
+}
// Root component for all Ink apps
// It renders stdin and stdout contexts, so that children can access them if needed
@@ -16,7 +88,9 @@ export default class App extends PureComponent {
stdin: PropTypes.object.isRequired,
stdout: PropTypes.object.isRequired,
exitOnCtrlC: PropTypes.bool.isRequired,
- onExit: PropTypes.func.isRequired
+ onExit: PropTypes.func.isRequired,
+ window: PropTypes.object,
+ document: PropTypes.object
};
// Determines if TTY is supported on the provided stdin
@@ -33,6 +107,14 @@ export default class App extends PureComponent {
}
render() {
+ const keyboardEventDispatcher = (this.props.window && this.props.document) ? (
+
+ ) : null;
return (
+ {keyboardEventDispatcher}
{this.props.children}
diff --git a/src/instance.js b/src/instance.js
index 703d1b664..e6c95b147 100644
--- a/src/instance.js
+++ b/src/instance.js
@@ -102,6 +102,8 @@ export default class Instance {