Imported Upstream version 0.2.1
Mike Gabriel
9 years ago
0 | ||
1 | /** | |
2 | * Module dependencies. | |
3 | */ | |
4 | ||
5 | var EventEmitter = require('events').EventEmitter; | |
6 | ||
7 | /** | |
8 | * Module exports. | |
9 | */ | |
10 | ||
11 | var exports = module.exports = keypress; | |
0 | 12 | |
1 | 13 | /** |
2 | 14 | * This module offers the internal "keypress" functionality from node-core's |
3 | 15 | * `readline` module, for your own programs and modules to use. |
4 | 16 | * |
17 | * The `keypress` function accepts a readable Stream instance and makes it | |
18 | * emit "keypress" events. | |
19 | * | |
5 | 20 | * Usage: |
6 | 21 | * |
7 | * require('keypress')(process.stdin); | |
8 | * | |
9 | * process.stdin.on('keypress', function (ch, key) { | |
10 | * console.log(ch, key); | |
11 | * if (key.ctrl && key.name == 'c') { | |
12 | * process.stdin.pause(); | |
13 | * } | |
14 | * }); | |
15 | * proces.stdin.resume(); | |
16 | */ | |
17 | var exports = module.exports = keypress; | |
18 | ||
19 | exports.enableMouse = function (stream) { | |
20 | stream.write('\x1b' +'[?1000h') | |
21 | } | |
22 | ||
23 | exports.disableMouse = function (stream) { | |
24 | stream.write('\x1b' +'[?1000l') | |
25 | } | |
26 | ||
27 | ||
28 | /** | |
29 | * accepts a readable Stream instance and makes it emit "keypress" events | |
22 | * ``` js | |
23 | * require('keypress')(process.stdin); | |
24 | * | |
25 | * process.stdin.on('keypress', function (ch, key) { | |
26 | * console.log(ch, key); | |
27 | * if (key.ctrl && key.name == 'c') { | |
28 | * process.stdin.pause(); | |
29 | * } | |
30 | * }); | |
31 | * proces.stdin.resume(); | |
32 | * ``` | |
33 | * | |
34 | * @param {Stream} stream | |
35 | * @api public | |
30 | 36 | */ |
31 | 37 | |
32 | 38 | function keypress(stream) { |
33 | 39 | if (isEmittingKeypress(stream)) return; |
34 | stream._emitKeypress = true; | |
40 | ||
41 | var StringDecoder = require('string_decoder').StringDecoder; // lazy load | |
42 | stream._keypressDecoder = new StringDecoder('utf8'); | |
35 | 43 | |
36 | 44 | function onData(b) { |
37 | if (stream.listeners('keypress').length > 0) { | |
38 | emitKey(stream, b); | |
45 | if (listenerCount(stream, 'keypress') > 0) { | |
46 | var r = stream._keypressDecoder.write(b); | |
47 | if (r) emitKey(stream, r); | |
39 | 48 | } else { |
40 | 49 | // Nobody's watching anyway |
41 | 50 | stream.removeListener('data', onData); |
50 | 59 | } |
51 | 60 | } |
52 | 61 | |
53 | if (stream.listeners('keypress').length > 0) { | |
62 | if (listenerCount(stream, 'keypress') > 0) { | |
54 | 63 | stream.on('data', onData); |
55 | 64 | } else { |
56 | 65 | stream.on('newListener', onNewListener); |
60 | 69 | /** |
61 | 70 | * Returns `true` if the stream is already emitting "keypress" events. |
62 | 71 | * `false` otherwise. |
72 | * | |
73 | * @param {Stream} stream readable stream | |
74 | * @return {Boolean} `true` if the stream is emitting "keypress" events | |
75 | * @api private | |
63 | 76 | */ |
64 | 77 | |
65 | 78 | function isEmittingKeypress(stream) { |
66 | var rtn = stream._emitKeypress; | |
79 | var rtn = !!stream._keypressDecoder; | |
67 | 80 | if (!rtn) { |
68 | // hack: check for the v0.6.x "data" event | |
69 | stream.listeners('data').forEach(function (l) { | |
81 | // XXX: for older versions of node (v0.6.x, v0.8.x) we want to remove the | |
82 | // existing "data" and "newListener" keypress events since they won't include | |
83 | // this `keypress` module extensions (like "mousepress" events). | |
84 | stream.listeners('data').slice(0).forEach(function(l) { | |
70 | 85 | if (l.name == 'onData' && /emitKey/.test(l.toString())) { |
71 | rtn = true; | |
72 | stream._emitKeypress = true; | |
86 | stream.removeListener('data', l); | |
73 | 87 | } |
74 | 88 | }); |
75 | } | |
76 | if (!rtn) { | |
77 | // hack: check for the v0.6.x "newListener" event | |
78 | stream.listeners('newListener').forEach(function (l) { | |
89 | stream.listeners('newListener').slice(0).forEach(function(l) { | |
79 | 90 | if (l.name == 'onNewListener' && /keypress/.test(l.toString())) { |
80 | rtn = true; | |
81 | stream._emitKeypress = true; | |
91 | stream.removeListener('newListener', l); | |
82 | 92 | } |
83 | 93 | }); |
84 | 94 | } |
85 | 95 | return rtn; |
86 | 96 | } |
97 | ||
98 | /** | |
99 | * Enables "mousepress" events on the *input* stream. Note that `stream` must be | |
100 | * an *output* stream (i.e. a Writable Stream instance), usually `process.stdout`. | |
101 | * | |
102 | * @param {Stream} stream writable stream instance | |
103 | * @api public | |
104 | */ | |
105 | ||
106 | exports.enableMouse = function (stream) { | |
107 | stream.write('\x1b[?1000h'); | |
108 | }; | |
109 | ||
110 | /** | |
111 | * Disables "mousepress" events from being sent to the *input* stream. | |
112 | * Note that `stream` must be an *output* stream (i.e. a Writable Stream instance), | |
113 | * usually `process.stdout`. | |
114 | * | |
115 | * @param {Stream} stream writable stream instance | |
116 | * @api public | |
117 | */ | |
118 | ||
119 | exports.disableMouse = function (stream) { | |
120 | stream.write('\x1b[?1000l'); | |
121 | }; | |
122 | ||
123 | /** | |
124 | * `EventEmitter.listenerCount()` polyfill, for backwards compat. | |
125 | * | |
126 | * @param {Emitter} emitter event emitter instance | |
127 | * @param {String} event event name | |
128 | * @return {Number} number of listeners for `event` | |
129 | * @api public | |
130 | */ | |
131 | ||
132 | var listenerCount = EventEmitter.listenerCount; | |
133 | if (!listenerCount) { | |
134 | listenerCount = function(emitter, event) { | |
135 | return emitter.listeners(event).length; | |
136 | }; | |
137 | } | |
138 | ||
139 | ||
140 | /////////////////////////////////////////////////////////////////////// | |
141 | // Below this function is code from node-core's `readline.js` module // | |
142 | /////////////////////////////////////////////////////////////////////// | |
87 | 143 | |
88 | 144 | |
89 | 145 | /* |
140 | 196 | |
141 | 197 | key.sequence = s; |
142 | 198 | |
143 | if (s === '\r' || s === '\n') { | |
144 | // enter | |
199 | if (s === '\r') { | |
200 | // carriage return | |
201 | key.name = 'return'; | |
202 | ||
203 | } else if (s === '\n') { | |
204 | // enter, should have been called linefeed | |
145 | 205 | key.name = 'enter'; |
146 | 206 | |
147 | 207 | } else if (s === '\t') { |
304 | 364 | return; |
305 | 365 | } |
306 | 366 | |
367 | // XXX: this "mouse" parsing code is NOT part of the node-core standard | |
368 | // `readline.js` module, and is a `keypress` module non-standard extension. | |
307 | 369 | if (key.code == '[M') { |
308 | 370 | key.name = 'mouse'; |
309 | 371 | var s = key.sequence; |
338 | 400 | } |
339 | 401 | |
340 | 402 | if (key && key.name == 'mouse') { |
341 | stream.emit('mousepress', key) | |
403 | stream.emit('mousepress', key); | |
342 | 404 | } else if (key || ch) { |
343 | 405 | stream.emit('keypress', ch, key); |
344 | 406 | } |