[Pkg-javascript-commits] [node-keypress] 01/14: Imported Upstream version 0.1.0

Mike Gabriel sunweaver at debian.org
Wed Aug 20 12:03:38 UTC 2014


This is an automated email from the git hooks/post-receive script.

sunweaver pushed a commit to branch master
in repository node-keypress.

commit 624f72ccf5ef00739b2f0b43b83b226b2731b4b6
Author: Mike Gabriel <mike.gabriel at das-netzwerkteam.de>
Date:   Thu May 9 14:00:21 2013 +0200

    Imported Upstream version 0.1.0
---
 README.md    | 101 +++++++++++++++++
 index.js     | 346 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 package.json |  20 ++++
 test.js      |  28 +++++
 4 files changed, 495 insertions(+)

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a768e8f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,101 @@
+keypress
+========
+### Make any Node ReadableStream emit "keypress" events
+
+
+Previous to Node `v0.8.x`, there was an undocumented `"keypress"` event that
+`process.stdin` would emit when it was a TTY. Some people discovered this hidden
+gem, and started using it in their own code.
+
+Now in Node `v0.8.x`, this `"keypress"` event does not get emitted by default,
+but rather only when it is being used in conjuction with the `readline` (or by
+extension, the `repl`) module.
+
+This module is the exact logic from the node `v0.8.x` releases ripped out into its
+own module.
+
+__Bonus:__ Now with mouse support!
+
+Installation
+------------
+
+Install with `npm`:
+
+``` bash
+$ npm install keypress
+```
+
+Or add it to the `"dependencies"` section of your _package.json_ file.
+
+
+Example
+-------
+
+#### Listening for "keypress" events
+
+``` js
+var keypress = require('keypress');
+
+// make `process.stdin` begin emitting "keypress" events
+keypress(process.stdin);
+
+// listen for the "keypress" event
+process.stdin.on('keypress', function (ch, key) {
+  console.log('got "keypress"', key);
+  if (key && key.ctrl && key.name == 'c') {
+    process.stdin.pause();
+  }
+});
+
+process.stdin.setRawMode(true);
+process.stdin.resume();
+```
+
+#### Listening for "mousepress" events
+
+``` js
+var keypress = require('keypress');
+
+// make `process.stdin` begin emitting "mousepress" (and "keypress") events
+keypress(process.stdin);
+
+// you must enable the mouse events before they will begin firing
+keypress.enableMouse(process.stdout);
+
+process.stdin.on('mousepress', function (info) {
+  console.log('got "mousepress" event at %d x %d', info.x, info.y);
+});
+
+process.on('exit', function () {
+  // disable mouse on exit, so that the state
+  // is back to normal for the terminal
+  keypress.disableMouse(process.stdout);
+});
+```
+
+
+License
+-------
+
+(The MIT License)
+
+Copyright (c) 2012 Nathan Rajlich <nathan at tootallnate.net>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..c2ba488
--- /dev/null
+++ b/index.js
@@ -0,0 +1,346 @@
+
+/**
+ * This module offers the internal "keypress" functionality from node-core's
+ * `readline` module, for your own programs and modules to use.
+ *
+ * Usage:
+ *
+ *   require('keypress')(process.stdin);
+ *
+ *   process.stdin.on('keypress', function (ch, key) {
+ *     console.log(ch, key);
+ *     if (key.ctrl && key.name == 'c') {
+ *       process.stdin.pause();
+ *     }
+ *   });
+ *   proces.stdin.resume();
+ */
+var exports = module.exports = keypress;
+
+exports.enableMouse = function (stream) {
+  stream.write('\x1b' +'[?1000h')
+}
+
+exports.disableMouse = function (stream) {
+  stream.write('\x1b' +'[?1000l')
+}
+
+
+/**
+ * accepts a readable Stream instance and makes it emit "keypress" events
+ */
+
+function keypress(stream) {
+  if (isEmittingKeypress(stream)) return;
+  stream._emitKeypress = true;
+
+  function onData(b) {
+    if (stream.listeners('keypress').length > 0) {
+      emitKey(stream, b);
+    } 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.listeners('keypress').length > 0) {
+    stream.on('data', onData);
+  } else {
+    stream.on('newListener', onNewListener);
+  }
+}
+
+/**
+ * Returns `true` if the stream is already emitting "keypress" events.
+ * `false` otherwise.
+ */
+
+function isEmittingKeypress(stream) {
+  var rtn = stream._emitKeypress;
+  if (!rtn) {
+    // hack: check for the v0.6.x "data" event
+    stream.listeners('data').forEach(function (l) {
+      if (l.name == 'onData' && /emitKey/.test(l.toString())) {
+        rtn = true;
+        stream._emitKeypress = true;
+      }
+    });
+  }
+  if (!rtn) {
+    // hack: check for the v0.6.x "newListener" event
+    stream.listeners('newListener').forEach(function (l) {
+      if (l.name == 'onNewListener' && /keypress/.test(l.toString())) {
+        rtn = true;
+        stream._emitKeypress = true;
+      }
+    });
+  }
+  return rtn;
+}
+
+
+/*
+  Some patterns seen in terminal key escape codes, derived from combos seen
+  at http://www.midnight-commander.org/browser/lib/tty/key.c
+
+  ESC letter
+  ESC [ letter
+  ESC [ modifier letter
+  ESC [ 1 ; modifier letter
+  ESC [ num char
+  ESC [ num ; modifier char
+  ESC O letter
+  ESC O modifier letter
+  ESC O 1 ; modifier letter
+  ESC N letter
+  ESC [ [ num ; modifier char
+  ESC [ [ 1 ; modifier letter
+  ESC ESC [ num char
+  ESC ESC O letter
+
+  - char is usually ~ but $ and ^ also happen with rxvt
+  - modifier is 1 +
+                (shift     * 1) +
+                (left_alt  * 2) +
+                (ctrl      * 4) +
+                (right_alt * 8)
+  - two leading ESCs apparently mean the same as one leading ESC
+*/
+
+// Regexes used for ansi escape code splitting
+var metaKeyCodeRe = /^(?:\x1b)([a-zA-Z0-9])$/;
+var functionKeyCodeRe =
+    /^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/;
+
+function emitKey(stream, s) {
+  var ch,
+      key = {
+        name: undefined,
+        ctrl: false,
+        meta: false,
+        shift: false
+      },
+      parts;
+
+  if (Buffer.isBuffer(s)) {
+    if (s[0] > 127 && s[1] === undefined) {
+      s[0] -= 128;
+      s = '\x1b' + s.toString(stream.encoding || 'utf-8');
+    } else {
+      s = s.toString(stream.encoding || 'utf-8');
+    }
+  }
+
+  key.sequence = s;
+
+  if (s === '\r' || s === '\n') {
+    // enter
+    key.name = 'enter';
+
+  } else if (s === '\t') {
+    // tab
+    key.name = 'tab';
+
+  } else if (s === '\b' || s === '\x7f' ||
+             s === '\x1b\x7f' || s === '\x1b\b') {
+    // backspace or ctrl+h
+    key.name = 'backspace';
+    key.meta = (s.charAt(0) === '\x1b');
+
+  } else if (s === '\x1b' || s === '\x1b\x1b') {
+    // escape key
+    key.name = 'escape';
+    key.meta = (s.length === 2);
+
+  } else if (s === ' ' || s === '\x1b ') {
+    key.name = 'space';
+    key.meta = (s.length === 2);
+
+  } else if (s <= '\x1a') {
+    // ctrl+letter
+    key.name = String.fromCharCode(s.charCodeAt(0) + 'a'.charCodeAt(0) - 1);
+    key.ctrl = true;
+
+  } else if (s.length === 1 && s >= 'a' && s <= 'z') {
+    // lowercase letter
+    key.name = s;
+
+  } else if (s.length === 1 && s >= 'A' && s <= 'Z') {
+    // shift+letter
+    key.name = s.toLowerCase();
+    key.shift = true;
+
+  } else if (parts = metaKeyCodeRe.exec(s)) {
+    // meta+character key
+    key.name = parts[1].toLowerCase();
+    key.meta = true;
+    key.shift = /^[A-Z]$/.test(parts[1]);
+
+  } else if (parts = functionKeyCodeRe.exec(s)) {
+    // ansi escape sequence
+
+    // reassemble the key code leaving out leading \x1b's,
+    // the modifier key bitflag and any meaningless "1;" sequence
+    var code = (parts[1] || '') + (parts[2] || '') +
+               (parts[4] || '') + (parts[6] || ''),
+        modifier = (parts[3] || parts[5] || 1) - 1;
+
+    // Parse the key modifier
+    key.ctrl = !!(modifier & 4);
+    key.meta = !!(modifier & 10);
+    key.shift = !!(modifier & 1);
+    key.code = code;
+
+    // Parse the key itself
+    switch (code) {
+      /* xterm/gnome ESC O letter */
+      case 'OP': key.name = 'f1'; break;
+      case 'OQ': key.name = 'f2'; break;
+      case 'OR': key.name = 'f3'; break;
+      case 'OS': key.name = 'f4'; break;
+
+      /* xterm/rxvt ESC [ number ~ */
+      case '[11~': key.name = 'f1'; break;
+      case '[12~': key.name = 'f2'; break;
+      case '[13~': key.name = 'f3'; break;
+      case '[14~': key.name = 'f4'; break;
+
+      /* from Cygwin and used in libuv */
+      case '[[A': key.name = 'f1'; break;
+      case '[[B': key.name = 'f2'; break;
+      case '[[C': key.name = 'f3'; break;
+      case '[[D': key.name = 'f4'; break;
+      case '[[E': key.name = 'f5'; break;
+
+      /* common */
+      case '[15~': key.name = 'f5'; break;
+      case '[17~': key.name = 'f6'; break;
+      case '[18~': key.name = 'f7'; break;
+      case '[19~': key.name = 'f8'; break;
+      case '[20~': key.name = 'f9'; break;
+      case '[21~': key.name = 'f10'; break;
+      case '[23~': key.name = 'f11'; break;
+      case '[24~': key.name = 'f12'; break;
+
+      /* xterm ESC [ letter */
+      case '[A': key.name = 'up'; break;
+      case '[B': key.name = 'down'; break;
+      case '[C': key.name = 'right'; break;
+      case '[D': key.name = 'left'; break;
+      case '[E': key.name = 'clear'; break;
+      case '[F': key.name = 'end'; break;
+      case '[H': key.name = 'home'; break;
+
+      /* xterm/gnome ESC O letter */
+      case 'OA': key.name = 'up'; break;
+      case 'OB': key.name = 'down'; break;
+      case 'OC': key.name = 'right'; break;
+      case 'OD': key.name = 'left'; break;
+      case 'OE': key.name = 'clear'; break;
+      case 'OF': key.name = 'end'; break;
+      case 'OH': key.name = 'home'; break;
+
+      /* xterm/rxvt ESC [ number ~ */
+      case '[1~': key.name = 'home'; break;
+      case '[2~': key.name = 'insert'; break;
+      case '[3~': key.name = 'delete'; break;
+      case '[4~': key.name = 'end'; break;
+      case '[5~': key.name = 'pageup'; break;
+      case '[6~': key.name = 'pagedown'; break;
+
+      /* putty */
+      case '[[5~': key.name = 'pageup'; break;
+      case '[[6~': key.name = 'pagedown'; break;
+
+      /* rxvt */
+      case '[7~': key.name = 'home'; break;
+      case '[8~': key.name = 'end'; break;
+
+      /* rxvt keys with modifiers */
+      case '[a': key.name = 'up'; key.shift = true; break;
+      case '[b': key.name = 'down'; key.shift = true; break;
+      case '[c': key.name = 'right'; key.shift = true; break;
+      case '[d': key.name = 'left'; key.shift = true; break;
+      case '[e': key.name = 'clear'; key.shift = true; break;
+
+      case '[2$': key.name = 'insert'; key.shift = true; break;
+      case '[3$': key.name = 'delete'; key.shift = true; break;
+      case '[5$': key.name = 'pageup'; key.shift = true; break;
+      case '[6$': key.name = 'pagedown'; key.shift = true; break;
+      case '[7$': key.name = 'home'; key.shift = true; break;
+      case '[8$': key.name = 'end'; key.shift = true; break;
+
+      case 'Oa': key.name = 'up'; key.ctrl = true; break;
+      case 'Ob': key.name = 'down'; key.ctrl = true; break;
+      case 'Oc': key.name = 'right'; key.ctrl = true; break;
+      case 'Od': key.name = 'left'; key.ctrl = true; break;
+      case 'Oe': key.name = 'clear'; key.ctrl = true; break;
+
+      case '[2^': key.name = 'insert'; key.ctrl = true; break;
+      case '[3^': key.name = 'delete'; key.ctrl = true; break;
+      case '[5^': key.name = 'pageup'; key.ctrl = true; break;
+      case '[6^': key.name = 'pagedown'; key.ctrl = true; break;
+      case '[7^': key.name = 'home'; key.ctrl = true; break;
+      case '[8^': key.name = 'end'; key.ctrl = true; break;
+
+      /* misc. */
+      case '[Z': key.name = 'tab'; key.shift = true; break;
+      default: key.name = 'undefined'; break;
+
+    }
+  } else if (s.length > 1 && s[0] !== '\x1b') {
+    // Got a longer-than-one string of characters.
+    // Probably a paste, since it wasn't a control sequence.
+    Array.prototype.forEach.call(s, function(c) {
+      emitKey(stream, c);
+    });
+    return;
+  }
+
+  if (key.code == '[M') {
+    key.name = 'mouse';
+    var s = key.sequence;
+    var b = s.charCodeAt(3);
+    key.x = s.charCodeAt(4) - 040;
+    key.y = s.charCodeAt(5) - 040;
+
+    key.scroll = 0;
+
+    key.ctrl  = !!(1<<4 & b);
+    key.meta  = !!(1<<3 & b);
+    key.shift = !!(1<<2 & b);
+
+    key.release = (3 & b) === 3;
+
+    if (1<<6 & b) { //scroll
+      key.scroll = 1 & b ? 1 : -1;
+    }
+
+    if (!key.release && !key.scroll) {
+      key.button = b & 3;
+    }
+  }
+
+  // Don't emit a key if no name was found
+  if (key.name === undefined) {
+    key = undefined;
+  }
+
+  if (s.length === 1) {
+    ch = s;
+  }
+
+  if (key && key.name == 'mouse') {
+    stream.emit('mousepress', key)
+  } else if (key || ch) {
+    stream.emit('keypress', ch, key);
+  }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..a527801
--- /dev/null
+++ b/package.json
@@ -0,0 +1,20 @@
+{
+  "name": "keypress",
+  "version": "0.1.0",
+  "description": "Make any Node ReadableStream emit \"keypress\" events",
+  "author": "Nathan Rajlich <nathan at tootallnate.net> (http://tootallnate.net)",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/TooTallNate/keypress.git"
+  },
+  "keywords": [
+    "keypress",
+    "readline",
+    "core"
+  ],
+  "license": "MIT"
+}
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..c3f61d7
--- /dev/null
+++ b/test.js
@@ -0,0 +1,28 @@
+
+var keypress = require('./')
+keypress(process.stdin)
+
+if (process.stdin.setRawMode)
+  process.stdin.setRawMode(true)
+else
+  require('tty').setRawMode(true)
+
+process.stdin.on('keypress', function (c, key) {
+  console.log(0, c, key)
+  if (key && key.ctrl && key.name == 'c') {
+    process.stdin.pause()
+  }
+})
+process.stdin.on('mousepress', function (mouse) {
+  console.log(mouse)
+})
+
+keypress.enableMouse(process.stdout)
+process.on('exit', function () {
+  //disable mouse on exit, so that the state is back to normal
+  //for the terminal.
+  keypress.disableMouse(process.stdout)
+})
+
+process.stdin.resume()
+

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-keypress.git



More information about the Pkg-javascript-commits mailing list