accepts a readable Stream instance and makes it emit "keypress" events
function emitKeypressEvents(stream, iface) {
  if (stream[KEYPRESS_DECODER]) return;

  if (StringDecoder === undefined)
    StringDecoder = require('string_decoder').StringDecoder;
  stream[KEYPRESS_DECODER] = new StringDecoder('utf8');

  stream[ESCAPE_DECODER] = emitKeys(stream);
  stream[ESCAPE_DECODER].next();

  const escapeCodeTimeout = () => stream[ESCAPE_DECODER].next('');
  let timeoutId;

  function onData(b) {
    if (stream.listenerCount('keypress') > 0) {
      var r = stream[KEYPRESS_DECODER].write(b);
      if (r) {
        clearTimeout(timeoutId);

        if (iface) {
          iface._sawKeyPress = r.length === 1;
        }

        for (var i = 0; i < r.length; i++) {
          if (r[i] === '\t' && typeof r[i + 1] === 'string' && iface) {
            iface.isCompletionEnabled = false;
          }

          try {
            stream[ESCAPE_DECODER].next(r[i]);
            // Escape letter at the tail position
            if (r[i] === kEscape && i + 1 === r.length) {
              timeoutId = setTimeout(
                escapeCodeTimeout,
                iface ? iface.escapeCodeTimeout : ESCAPE_CODE_TIMEOUT
              );
            }
          } catch (err) {
            // If the generator throws (it could happen in the `keypress`
            // event), we need to restart it.
            stream[ESCAPE_DECODER] = emitKeys(stream);
            stream[ESCAPE_DECODER].next();
            throw err;
          } finally {
            if (iface) {
              iface.isCompletionEnabled = true;
            }
          }
        }
      }
    } else {
      // Nobody's watching anyway
      stream.removeListener('data', onData);
      stream.on('newListener', onNewListener);
    }
  }

  function onNewListener(event) {
    if (event === 'keypress') {
      stream.on('data', onData);
      stream.removeListener('newListener', onNewListener);
    }
  }

  if (stream.listenerCount('keypress') > 0) {
    stream.on('data', onData);
  } else {
    stream.on('newListener', onNewListener);
  }
}