[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