From 7113bb6c2db07f3089a45840236eda68f26d984e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Wed, 22 Apr 2015 00:36:35 +0200 Subject: [PATCH 01/28] reworking structure --- .gitmodules | 3 + .travis.yml | 2 + binding.gyp | 8 +- build.js | 12 +- deps/ee.c | 1 + deps/ee/ee.c | 199 ------------ deps/ee/ee.h | 92 ------ examples/emit.js | 13 - examples/input.js | 26 -- examples/output.js | 7 - export.js | 111 ++++--- include/generated.h | 14 +- include/nauv.h | 38 +++ include/ttyu.h | 171 +++-------- include/unix.h | 106 ++----- include/util.h | 64 ---- include/utils.h | 94 ++++++ include/win.h | 122 ++++++-- package.json | 1 + signal.js | 42 +-- src/ttyu.cc | 47 ++- src/ttyu_event.cc | 20 +- src/ttyu_js.cc | 161 ---------- src/ttyu_worker.cc | 159 ---------- src/unix.cc | 617 +++++++++++++++++--------------------- src/{util.cc => utils.cc} | 127 ++++---- src/win.cc | 527 +++----------------------------- 27 files changed, 813 insertions(+), 1971 deletions(-) create mode 100644 .gitmodules mode change 100755 => 100644 binding.gyp create mode 160000 deps/ee.c delete mode 100644 deps/ee/ee.c delete mode 100644 deps/ee/ee.h delete mode 100644 examples/emit.js delete mode 100644 examples/input.js delete mode 100644 examples/output.js create mode 100644 include/nauv.h delete mode 100644 include/util.h create mode 100644 include/utils.h delete mode 100644 src/ttyu_js.cc delete mode 100644 src/ttyu_worker.cc rename src/{util.cc => utils.cc} (62%) diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ca715d7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "deps/ee.c"] + path = deps/ee.c + url = https://github.com/bbuecherl/ee.c.git diff --git a/.travis.yml b/.travis.yml index e3445c9..e84f4a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,5 +9,7 @@ node_js: - "iojs-v1.6.4" install: - npm install + - curl -G -v http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py -o cpplint.py script: + - npm run-script lint - npm test diff --git a/binding.gyp b/binding.gyp old mode 100755 new mode 100644 index 09f0ccd..213ad49 --- a/binding.gyp +++ b/binding.gyp @@ -4,16 +4,14 @@ "target_name": "ttyu", "include_dirs" : [ "\n" + + " *\n" + " * do not change, this file is autogenerated by 'node build',\n" + " * these constants are set in ./const.js\n" + " * Build: " + pkg.version + "." + Date.now() + "\n" + " */\n" + - "#ifndef TTYU_GENERATED_H_\n" + - "#define TTYU_GENERATED_H_\n" + + "#ifndef INCLUDE_GENERATED_H_\n" + + "#define INCLUDE_GENERATED_H_\n" + "\n"; for(var name in Const) { @@ -23,7 +27,7 @@ for(var name in Const) { cont += "\n"; } -cont += "#endif // TTYU_GENERATED_H_\n"; +cont += "#endif // INCLUDE_GENERATED_H_\n"; fs.writeFile(generated, cont, console.log); diff --git a/deps/ee.c b/deps/ee.c new file mode 160000 index 0000000..4c1a791 --- /dev/null +++ b/deps/ee.c @@ -0,0 +1 @@ +Subproject commit 4c1a7910451732d6352f286926a60aa6b17a8db2 diff --git a/deps/ee/ee.c b/deps/ee/ee.c deleted file mode 100644 index 3cd3d33..0000000 --- a/deps/ee/ee.c +++ /dev/null @@ -1,199 +0,0 @@ -/* ee - eventemitter for c - ee.c - * https://github.com/clidejs/ee.c - * - * Copyright Bernhard Bücherl - * - * 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. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -// header file -#include "ee.h" - -// for malloc, free -#include - -// initialize empty emitter -void ee_init(ee_emitter_t *emitter, - int (*emit)(ee__listener_t *, EE_DATA_TYPE), - int (*compare)(EE_CB_ARG(cb1), EE_CB_ARG(cb2))) { - emitter->root = 0; - emitter->emit = emit; - emitter->compare = compare; -} - -void ee_on(ee_emitter_t *emitter, int event, EE_CB_ARG(cb)) { - ee__event_t *ev; - if(emitter->root == 0) { - ev = ee__event_new(event); - emitter->root = ev; - } else if(emitter->root->id == event) { - ev = emitter->root; - } else { - ev = ee__event_find(emitter->root, event); - } - if(ev->root == 0) { - ev->root = ee__listener_new(cb); - } else { - ee__listener_add(ev->root, cb); - } -} - -void ee_off(ee_emitter_t *emitter, int event, EE_CB_ARG(cb)) { - ee__event_t *ev; - if(emitter->root == 0) { - return; - } else if(emitter->root->id == event) { - ev = emitter->root; - } else { - ev = ee__event_find(emitter->root, event); - } - if(ev->root == 0) { - return; - } else if((emitter->compare && emitter->compare(ev->root->cb, cb)) || - ev->root->cb == cb) { - ee__listener_t *old = ev->root; - ev->root = old->next; - ee__listener_destroy(old); - } else { - ee__listener_remove(emitter, ev->root, cb); - } -} - -int ee_emit(ee_emitter_t *emitter, int event, EE_DATA_ARG(data)) { - ee__listener_t *l; - int count = 0; - if(emitter->root == 0) { - return count; - } else if(emitter->root->id == event) { - l = emitter->root->root; - } else { - l = ee__event_find(emitter->root, event)->root; - } - if(l != 0) { - if(emitter->emit) { - return emitter->emit(l, data); - } else { - do { - if(l->cb) { - l->cb(data); - } - ++count; - } while((l = l->next)); - } - } - return count; -} - -int ee_count(ee_emitter_t *emitter, int event) { - ee__listener_t *l; - int count = 0; - if(emitter->root == 0) { - return count; - } else if(emitter->root->id == event) { - l = emitter->root->root; - } else { - l = ee__event_find(emitter->root, event)->root; - } - if(l != 0) { - do { - ++count; - } while((l = l->next)); - } - return count; -} - -void ee_destroy(ee_emitter_t *emitter) { - ee__event_t *tmp; - while((tmp = emitter->root)) { - emitter->root = tmp->next; - ee__event_destroy(tmp); - } -} - -ee__listener_t *ee__listener_new(EE_CB_ARG(cb)) { - ee__listener_t *new_listener = - (ee__listener_t *)malloc(sizeof(ee__listener_t)); - new_listener->next = 0; - new_listener->cb = cb; - return new_listener; -} - -ee__listener_t *ee__listener_add(ee__listener_t *listener, EE_CB_ARG(cb)) { - if(listener->next == 0) { - return (listener->next = ee__listener_new(cb)); - } else { - return ee__listener_add(listener->next, cb); - } -} - -void ee__listener_remove(ee_emitter_t *emitter, ee__listener_t *listener, - EE_CB_ARG(cb)) { - if(listener->next != 0) { - if((emitter->compare && emitter->compare(listener->next->cb, cb)) || - listener->next->cb == cb) { - ee__listener_t *old = listener->next; - listener->next = old->next; - ee__listener_destroy(old); - } else { - ee__listener_remove(emitter, listener->next, cb); - } - } -} - -void ee__listener_destroy(ee__listener_t *listener) { - listener->next = 0; - listener->cb = 0; - free(listener); -} - -ee__event_t *ee__event_new(int event) { - ee__event_t *new_event = (ee__event_t *)malloc(sizeof(ee__event_t)); - new_event->id = event; - new_event->next = 0; - new_event->root = 0; - return new_event; -} - -ee__event_t *ee__event_find(ee__event_t *element, int event) { - if(element->next == 0) { - return (element->next = ee__event_new(event)); - } else if(element->next->id == event) { - return element->next; - } else { - return ee__event_find(element->next, event); - } -} - -void ee__event_destroy(ee__event_t *element) { - ee__listener_t *tmp; - element->next = 0; - while((tmp = element->root)) { - element->root = tmp->next; - ee__listener_destroy(tmp); - } - free(element); -} - -#ifdef __cplusplus -} -#endif diff --git a/deps/ee/ee.h b/deps/ee/ee.h deleted file mode 100644 index 642cd8a..0000000 --- a/deps/ee/ee.h +++ /dev/null @@ -1,92 +0,0 @@ -/* ee - eventemitter for c - ee.h - * https://github.com/clidejs/ee.c - * - * Copyright Bernhard Bücherl - * - * 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. - */ - -#ifndef EE_H_ -#define EE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef EE_DATA_TYPE -#define EE_DATA_TYPE void * -#endif - -#ifndef EE_DATA_ARG -#define EE_DATA_ARG(name) EE_DATA_TYPE name -#endif - -#ifndef EE_CB_TYPE -#define EE_CB_TYPE void(*) (EE_DATA_TYPE) -#endif - -#ifndef EE_CB_ARG -#define EE_CB_ARG(name) void(*name)(EE_DATA_TYPE) -#endif - -typedef struct ee__event_s ee__event_t; -typedef struct ee__listener_s ee__listener_t; -typedef struct ee_emitter_s ee_emitter_t; - -struct ee__event_s { - int id; // event identifier - ee__event_t *next; - ee__listener_t *root; -}; - -struct ee__listener_s { - EE_CB_ARG(cb); - ee__listener_t *next; -}; - -struct ee_emitter_s { - ee__event_t *root; - int (*emit)(ee__listener_t *, EE_DATA_TYPE); - int (*compare)(EE_CB_TYPE, EE_CB_TYPE); -}; - -void ee_init(ee_emitter_t *emitter, - int (*emit)(ee__listener_t *, EE_DATA_TYPE), - int (*compare)(EE_CB_TYPE, EE_CB_TYPE)); -void ee_on(ee_emitter_t *emitter, int event, EE_CB_ARG(cb)); -void ee_off(ee_emitter_t *emitter, int event, EE_CB_ARG(cb)); -int ee_emit(ee_emitter_t *emitter, int event, EE_DATA_ARG(data)); -int ee_count(ee_emitter_t *emitter, int event); -void ee_destroy(ee_emitter_t *emitter); - -ee__listener_t *ee__listener_new(EE_CB_ARG(cb)); -ee__listener_t *ee__listener_add(ee__listener_t *listener, EE_CB_ARG(cb)); -void ee__listener_remove(ee_emitter_t *emitter, ee__listener_t *listener, - EE_CB_ARG(cb)); -void ee__listener_destroy(ee__listener_t *listener); - -ee__event_t *ee__event_new(int event); -ee__event_t *ee__event_find(ee__event_t *element, int event); -void ee__event_destroy(ee__event_t *element); - -#ifdef __cplusplus -} -#endif - -#endif // EE_H_ diff --git a/examples/emit.js b/examples/emit.js deleted file mode 100644 index d4bb3b4..0000000 --- a/examples/emit.js +++ /dev/null @@ -1,13 +0,0 @@ -var TTYUtil = require("../index"); - -var ttyu = new TTYUtil(); - -ttyu.on(TTYUtil.EVENT.KEY, function(ev) { - ttyu.write(JSON.stringify(ev) + "\r\n"); -}); - -ttyu.start(); - -setTimeout(function() { - ttyu.emit(TTYUtil.EVENT.KEY, 65, 4); -}, 10); diff --git a/examples/input.js b/examples/input.js deleted file mode 100644 index ef8eee2..0000000 --- a/examples/input.js +++ /dev/null @@ -1,26 +0,0 @@ -var TTYUtil = require("../index"); - -var ttyu = new TTYUtil(); - -for(var event in TTYUtil.EVENT) { - ttyu.on(TTYUtil.EVENT[event], listener(TTYUtil.EVENT[event])); -} - -var l = function(ev) { - ttyu.write("asdf"); -} - -ttyu.on(TTYUtil.EVENT.KEY, l); - -function listener(name) { - return function(ev) { - ttyu.write(name + ": " + JSON.stringify(ev) + "\r\n", name === "error" ? - "#F00" : "#0F0", name === "error" ? "#400" : "#040"); - if(name === "signal") { - ttyu.destroy(); - } - }; -} - -ttyu.start(); -ttyu.off(TTYUtil.EVENT.KEY, l); diff --git a/examples/output.js b/examples/output.js deleted file mode 100644 index 2c3e0d5..0000000 --- a/examples/output.js +++ /dev/null @@ -1,7 +0,0 @@ -var TTYUtil = require("../index"); - -var ttyu = new TTYUtil(); - -ttyu.start(); - -ttyu.write("Hello World", "#F00", "#365cff"); diff --git a/export.js b/export.js index 9dd8134..41cdb45 100644 --- a/export.js +++ b/export.js @@ -1,67 +1,82 @@ var Const = require("./const"); var signal = require("./signal"); -module.exports = function(ttyu) { - ttyu.TTYUtil.prototype.on = function(ev, listener) { - if(ev === ttyu.TTYUtil.EVENT.SIGNAL) { - signal.on(ttyu, this, listener); - } else if(ev in Const.Event && listener instanceof Function) { - this.__on__(Const.Event[ev], listener); - } - return this; - }; - ttyu.TTYUtil.prototype.off = - ttyu.TTYUtil.prototype.removeListener = function(ev, listener) { - if(ev === ttyu.TTYUtil.EVENT.SIGNAL) { - signal.off(this, listener); +module.exports = function(ttyu_js_c) { + var ttyu = new ttyu_js_c(); + + var ttyutil = { + start: function() { + ttyu.start(); + }, + stop: function() { + ttyu.stop(); + }, + write: function() { + ttyu.write.apply(ttyu, arguments); + }, + on: function(ev, listener) { + if(ev === ttyutil.EVENT.SIGNAL) { + signal.on(ttyu, ttyu, listener); + } else if(ev in Const.Event && listener instanceof Function) { + ttyu.on(Const.Event[ev], listener); + } + return ttyutil; + }, + removeListener: off, + emit:function(ev) { + switch(ev.type) { + case ttyutil.EVENT.SIGNAL: + signal.emit(ev.signal); + break; + case ttyutil.EVENT.KEY: + ttyu.emit(Const.Event[ev.type], ev.which, ev.ctrl); + break; + case ttyutil.EVENT.MOUSEDOWN: + case ttyutil.EVENT.MOUSEUP: + case ttyutil.EVENT.MOUSEMOVE: + case ttyutil.EVENT.MOUSEWHEEL: + case ttyutil.EVENT.MOUSEHWHEEL: + ttyu.emit(Const.Event[ev.type], ev.button, ev.x, ev.y, + ev.ctrl); + break; + default: + // ERROR, RESIZE + break; + } + }, + } + + function off(ev, listener) { + if(ev === ttyutil.EVENT.SIGNAL) { + signal.off(ttyu, listener); } else if(ev in Const.Event && listener instanceof Function) { - this.__off__(Const.Event[ev], listener); - } - return this; - }; - ttyu.TTYUtil.prototype.emit = function(ev) { - switch(ev.type) { - case ttyu.TTYUtil.EVENT.SIGNAL: - signal.emit(ev.signal); - break; - case ttyu.TTYUtil.EVENT.KEY: - this.__emit__(Const.Event[ev.type], ev.which, ev.ctrl); - break; - case ttyu.TTYUtil.EVENT.MOUSEDOWN: - case ttyu.TTYUtil.EVENT.MOUSEUP: - case ttyu.TTYUtil.EVENT.MOUSEMOVE: - case ttyu.TTYUtil.EVENT.MOUSEWHEEL: - case ttyu.TTYUtil.EVENT.MOUSEHWHEEL: - this.__emit__(Const.Event[ev.type], ev.button, ev.x, ev.y, - ev.ctrl); - break; - default: - // ERROR, RESIZE - break; + ttyu.off(Const.Event[ev], listener); } + return ttyutil; }; - ttyu.TTYUtil.SIGNAL = { + + ttyutil.SIGNAL = { SIGINT: "SIGINT", SIGTERM: "SIGTERM", SIGPIPE: "SIGPIPE", SIGHUP: "SIGHUP" }; - ttyu.TTYUtil.EVENT = Const.EventString; - ttyu.TTYUtil.MOUSE = Const.Mouse; - ttyu.TTYUtil.WHICH = Const.Which; - ttyu.TTYUtil.CTRL = Const.Ctrl; - ttyu.TTYUtil.MODE = Const.Mode; + ttyutil.EVENT = Const.EventString; + ttyutil.MOUSE = Const.Mouse; + ttyutil.WHICH = Const.Which; + ttyutil.CTRL = Const.Ctrl; + ttyutil.MODE = Const.Mode; // event constructors - ttyu.TTYUtil.KeyEvent = function(which, ctrl) { + ttyutil.KeyEvent = function(which, ctrl) { return { - type: ttyu.TTYUtil.EVENT.KEY, + type: ttyutil.EVENT.KEY, which: which, ctrl: ctrl }; }; - ttyu.TTYUtil.MouseEvent = function(type, button, x, y, ctrl) { + ttyutil.MouseEvent = function(type, button, x, y, ctrl) { return { type: type, button: button, @@ -70,12 +85,12 @@ module.exports = function(ttyu) { ctrl: ctrl }; }; - ttyu.TTYUtil.SignalEvent = function(signal) { + ttyutil.SignalEvent = function(signal) { return { - type: ttyu.TTYUtil.EVENT.SIGNAL, + type: ttyutil.EVENT.SIGNAL, signal: signal }; }; - return ttyu.TTYUtil; + return ttyutil; }; diff --git a/include/generated.h b/include/generated.h index 065e5b1..358a68d 100644 --- a/include/generated.h +++ b/include/generated.h @@ -1,10 +1,14 @@ -/** +/** ttyutil - generated.h - generated headers + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * * do not change, this file is autogenerated by 'node build', * these constants are set in ./const.js - * Build: 0.2.0.1428403644944 + * Build: 0.2.0.1429616750432 */ -#ifndef TTYU_GENERATED_H_ -#define TTYU_GENERATED_H_ +#ifndef INCLUDE_GENERATED_H_ +#define INCLUDE_GENERATED_H_ #define EVENT_ERROR 0 #define EVENT_SIGNAL 1 @@ -264,4 +268,4 @@ #define MODE_VT102 1 #define MODE_VT100 2 -#endif // TTYU_GENERATED_H_ +#endif // INCLUDE_GENERATED_H_ diff --git a/include/nauv.h b/include/nauv.h new file mode 100644 index 0000000..5e0b993 --- /dev/null +++ b/include/nauv.h @@ -0,0 +1,38 @@ +/* ttyutil - nauv.h - native abstractions for libuv extending nan.h + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#ifndef INCLUDE_NAUV_H_ +#define INCLUDE_NAUV_H_ + +#if NAUV_UVVERSION < 0x010000 +#define NAUV_BARRIER_WAIT(barrier, kill) \ + uv_barrier_wait(barrier); \ + if (kill) \ + uv_barrier_destroy(barrier); +#else +#define NAUV_BARRIER_WAIT(barrier, kill) \ + if (uv_barrier_wait(barrier) > 0) \ + uv_barrier_destroy(barrier); +#endif + +#endif // INCLUDE_NAUV_H_ diff --git a/include/ttyu.h b/include/ttyu.h index 9789916..1a41d7e 100644 --- a/include/ttyu.h +++ b/include/ttyu.h @@ -21,18 +21,15 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ +#ifndef INCLUDE_TTYU_H_ +#define INCLUDE_TTYU_H_ -#ifndef TTYU_H_ -#define TTYU_H_ +#include -#include -#include - -#include -#include #include +#include #include -#include "util.h" +#include // predefine event data and callbacks for ee.c #define EE_DATA_TYPE v8::Local @@ -49,21 +46,15 @@ # define FALSE 0 #endif +// more defines (extending ) +#define EVENT_NONE -1 +#define EMIT_INTERVAL 20 + // callback call function for the event emitter int ttyu_ee_cb_call(ee__listener_t *l, EE_DATA_ARG(data)); // callback compare function for the event emitter int ttyu_ee_compare(EE_CB_ARG(cb1), EE_CB_ARG(cb2)); -// predefine classes -class ttyu_js_c; -class ttyu_worker_c; - -// data structure for caching platform-dependent terminal handles -// these are defined in platform-dependent source and header files -typedef struct ttyu_data_s ttyu_data_t; -void ttyu_data_init(ttyu_data_t *data); -void ttyu_data_destroy(ttyu_data_t *data); - // key event structure typedef struct ttyu_key_s { int ctrl; @@ -93,123 +84,8 @@ void ttyu_event_create_mouse(ttyu_event_t *event, int type, int button, int x, int y, int ctrl); void ttyu_event_destroy(ttyu_event_t *event); -// helper functions for exception throwing -#define TTYU_THROW_IF_DESTROYED(obj) do { \ - if(obj->throw_ && obj->destroyed_) { \ - NanThrowError("TTYUtil object was already destroyed"); \ - NanReturnUndefined(); \ - } \ -} while(0) -#define TTYU_THROW_IF_NOT_RUNNING(obj) do { \ - TTYU_THROW_IF_DESTROYED(obj); \ - if(obj->throw_ && !obj->running) { \ - NanThrowError("TTYUtil object was not started"); \ - NanReturnUndefined(); \ - } \ -} while(0) -#define TTYU_THROW_IF_NOT_RUNNING_VOID(obj) do { \ - if(obj->throw_ && obj->destroyed_) { \ - NanThrowError("TTYUtil object was already destroyed"); \ - return; \ - } \ - if(obj->throw_ && !obj->running) { \ - NanThrowError("TTYUtil object was not started"); \ - return; \ - } \ -} while(0) - -// definition of the node module class -class ttyu_js_c : public node::ObjectWrap { -public: - static void init(v8::Handle target); - explicit ttyu_js_c(); - void destroy(); - - ttyu_data_t *data; - ee_emitter_t *emitter; - bool running; - bool paused; -#ifndef PLATFORM_WINDOWS - uv_barrier_t barrier; -#endif -private: - ~ttyu_js_c(); - - static NAN_METHOD(new_instance); - static NAN_METHOD(start); - static NAN_METHOD(pause); - static NAN_METHOD(destroy); - static NAN_METHOD(on); - static NAN_METHOD(off); - static NAN_METHOD(emit); - static NAN_GETTER(is_running); - static NAN_GETTER(get_width); - static NAN_GETTER(get_height); - static NAN_GETTER(get_mode); - static NAN_GETTER(get_colors); - static NAN_GETTER(getx); - static NAN_SETTER(setx); - static NAN_GETTER(gety); - static NAN_SETTER(sety); - static NAN_METHOD(gotoxy); - static NAN_METHOD(write); - static NAN_METHOD(beep); - static NAN_METHOD(clear); - static NAN_METHOD(prepare); - static NAN_METHOD(color); - - static v8::Persistent constructor; - - bool throw_; - bool destroyed_; - ttyu_worker_c *worker_; -}; - -// definition of the terminal input listener class -class ttyu_worker_c : public NanAsyncWorker { -public: - class ttyu_progress_c { - friend class ttyu_worker_c; - public: - void send(const ttyu_event_t *event) const; - private: - explicit ttyu_progress_c(ttyu_worker_c *that); - // prevent movement - ttyu_progress_c(const ttyu_progress_c&); - void operator=(const ttyu_progress_c&); -#if __cplusplus >= 201103L - ttyu_progress_c(const ttyu_progress_c&&) V8_DELETE; - void operator=(const ttyu_progress_c&&) V8_DELETE; -#endif - ttyu_worker_c *const that_; - }; - - ttyu_worker_c(ttyu_js_c *obj); - virtual ~ttyu_worker_c(); - - void progress(); - - bool execute(const ttyu_progress_c& progress, ttyu_data_t *data); - void handle(ttyu_event_t *event); - - virtual void Destroy(); - - void Execute(); - virtual void WorkComplete(); -private: - void send_(const ttyu_event_t *event); - - static NAUV_WORK_CB(async_progress_); - static void async_close_(uv_handle_t *handle); - - uv_async_t *async; - uv_mutex_t *async_lock; - ttyu_event_t *asyncdata_; - ttyu_js_c *obj_; -}; - -template class ttyu_queue_c; -template struct ttyu_queue_data_s; +// predefine data class +class ttyu_js_c; // include platform dependent headers #ifdef PLATFORM_WINDOWS @@ -218,4 +94,27 @@ template struct ttyu_queue_data_s; # include #endif -#endif // TTYU_H_ +class ttyu_js_c : public node::ObjectWrap { + public: + ttyu_js_c(); + ~ttyu_js_c(); + + static void init(v8::Handle exports, + v8::Handle module); + static NAN_METHOD(js_new); + static NAN_METHOD(js_start); + static NAN_METHOD(js_stop); + static NAN_METHOD(js_on); + static NAN_METHOD(js_off); + static NAN_METHOD(js_emit); + // static NAN_METHOD(js_running); + + static NAN_METHOD(js_write); + + bool running; + bool stop; + ee_emitter_t emitter; + PLATFORM_DEPENDENT_FIELDS; +}; + +#endif // INCLUDE_TTYU_H_ diff --git a/include/unix.h b/include/unix.h index 9c24013..0664a46 100644 --- a/include/unix.h +++ b/include/unix.h @@ -22,19 +22,12 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ -#ifndef TTYU_UNIX_H_ -#define TTYU_UNIX_H_ +#ifndef INCLUDE_UNIX_H_ +#define INCLUDE_UNIX_H_ #define NCURSES_OPAQUE FALSE #include -#include - -#define ERROR_UNIX_UNDEF "unknown error occured while reading input" -#define ERROR_UNIX_MOUSEBAD "skipping unreadable mouse event" -#define ERROR_UNIX_MOUSEUNCAUGHT "skipping unknown mouse event" - -#define TTYU_EXIT 2 -#define TTYU_UNKNOWN 1 +#include #define TTYU_UNIX_KW(XX) \ XX(WHICH_DOWN, KEY_DOWN, FALSE); \ @@ -103,78 +96,27 @@ \ XX(WHICH_SHIFT, 0, TRUE) -// thread save queue -template struct ttyu_queue_data_s; -template class ttyu_queue_c { -public: - ttyu_queue_c() : size_(0) { - uv_mutex_init(&mutex_); - } - - virtual ~ttyu_queue_c() { - uv_mutex_destroy(&mutex_); - } - - void push(T val) { - DBG("push has started"); - uv_mutex_lock(&mutex_); - queue_.push(&val); - uv_mutex_unlock(&mutex_); - DBG("push has finished"); - } - - T *pop() { - DBG("pop acquiring rdlock"); - uv_mutex_lock(&mutex_); - DBG("pop acquired rdlock"); - T *front = queue_.front(); - queue_.pop(); - uv_mutex_unlock(&mutex_); - DBG("pop released rdlock"); - return front; - } +TTYU_INLINE int ttyu_unix_which(int c); +TTYU_INLINE int ttyu_unix_key(int which); - int size() { - DBG("size has sarted"); - if(uv_mutex_trylock(&mutex_) == 0) { - DBG("size acquired rdlock"); - size_ = queue_.size(); - uv_mutex_unlock(&mutex_); - DBG("size released rdlock"); - } - return size_; - } - - bool empty() { - DBG("empty has sarted"); - if(uv_mutex_trylock(&mutex_) == 0) { - DBG("empty acquired rdlock"); - size_ = queue_.size(); - uv_mutex_unlock(&mutex_); - DBG("empty released rdlock"); - } - return (size_ == 0); - } - -private: - std::queue queue_; - uv_mutex_t mutex_; - int size_; -}; - -// unixy data structure -struct ttyu_data_s { - WINDOW *win; - mmask_t old_mouse_mask; - int mode; - bool closing; - - ttyu_queue_c ungetch_stack; - ttyu_queue_c ungetmouse_stack; -}; +#define PLATFORM_DEPENDENT_FIELDS \ + static void handle(uv_work_t *req); \ + static void complete(uv_work_t *req); \ + static void curses_thread_func(void *that); \ + static int curses_threaded_func(WINDOW *win, void *that); \ + \ + uv_thread_t curses_thread; \ + WINDOW *win; \ + uv_barrier_t barrier; \ + uv_mutex_t emitlock; \ + uv_mutex_t ungetlock; \ + int mode; \ + std::vector unget_stack; \ + std::vector emit_stack -void ttyu_unix_clrscr(ttyu_data_t *data, int x, int y, int width, int height); -int ttyu_unix_key(int which); -int ttyu_unix_which(int key); +typedef struct ttyu_work_s { + ttyu_event_t *event; + ttyu_js_c *data; +} ttyu_work_t; -#endif // TTYU_UNIX_H_ +#endif // INCLUDE_UNIX_H_ diff --git a/include/util.h b/include/util.h deleted file mode 100644 index a0cdb3f..0000000 --- a/include/util.h +++ /dev/null @@ -1,64 +0,0 @@ -/* ttyutil - util.h - header file to define utility methods, - * implementation in src/util.cc - * https://github.com/clidejs/ttyutil - * - * Copyright Bernhard Bücherl - * - * 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. - */ -#ifndef TTYU_UTIL_H_ -#define TTYU_UTIL_H_ - -#include -#include - -#define EXPORT_PROTOTYPE_METHOD NODE_SET_PROTOTYPE_METHOD -#define EXPORT_PROTOTYPE_METHOD_HIDDEN(tpl, name, cb) do { \ - v8::Local t = NanNew(cb); \ - tpl->InstanceTemplate()->Set( \ - NanNew(name), t->GetFunction(), v8::ReadOnly); \ -} while(0) - -#define EXPORT_PROTOTYPE_GET(tpl, name, fn) \ - tpl->InstanceTemplate()->SetAccessor(NanNew(name), (fn)) - -#define EXPORT_PROTOTYPE_GETSET(tpl, name, get, set) \ - tpl->InstanceTemplate()->SetAccessor(NanNew(name), (get), (set)) - -#define WIN_COLORS 16 - -short util_rgbi2term(short r, short g, short b); -short util_rgbi2win(short r, short g, short b); -char *util_render(const char *ch, short fg, short bg); -short util_parse_dec(char d); -short util_parse_hex(char h); -unsigned long util_term2argb(short t); -short util_rgb2term(const char *rgb); -short util_hex2term(const char *hex); -short util_color(const char *c); -int util_max(int a, int b); -int util_min(int a, int b); -int util_abs(int a); -char *util_error(char *name, int id); - -#undef ERROR -#define ERROR(name, id) util_error(name, id) -#define DBG(a) std::cout << (a) << "\r\n" - -#endif // TTYUTIL_UTIL_H_ diff --git a/include/utils.h b/include/utils.h new file mode 100644 index 0000000..4071a8f --- /dev/null +++ b/include/utils.h @@ -0,0 +1,94 @@ +/* ttyutil - util.h - header file to define utility methods, + * implementation in src/util.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#ifndef INCLUDE_UTILS_H_ +#define INCLUDE_UTILS_H_ + +#include + +#define EXPORT_METHOD(tpl, name, cb) do { \ + v8::Local t = NanNew(cb); \ + tpl->InstanceTemplate()->Set(NanNew(name), \ + t->GetFunction(), v8::ReadOnly); \ +} while (0) + +#define EXPORT_GET(tpl, name, fn) do { \ + v8::Local t = NanNew(fn); \ + tpl->InstanceTemplate()->SetAccessor(NanNew(name), \ + t->GetFunction()); \ +} while (0) + +#define EXPORT_GETSET(tpl, name, get, set) \ + tpl->InstanceTemplate()->SetAccessor(NanNew(name), (get), (set)) + +#if defined(__GNUC__) && !(defined(DEBUG) && DEBUG) +# define TTYU_INLINE inline __attribute__((always_inline)) +#elif defined(_MSC_VER) && !(defined(DEBUG) && DEBUG) +# define TTYU_INLINE __forceinline +#else +# define TTYU_INLINE inline +#endif + +#define WIN_COLORS 16 + +#define COLORS_ARRAY(XX, i) \ + XX(0, i, 0x000000) \ + XX(1, i, 0x800000) \ + XX(2, i, 0x008000) \ + XX(3, i, 0x808000) \ + XX(4, i, 0x000080) \ + XX(5, i, 0x800080) \ + XX(6, i, 0x008080) \ + XX(7, i, 0xc0c0c0) \ + XX(8, i, 0x808080) \ + XX(9, i, 0xff0000) \ + XX(10, i, 0x00ff00) \ + XX(11, i, 0xffff00) \ + XX(12, i, 0x0000ff) \ + XX(13, i, 0xff00ff) \ + XX(14, i, 0x00ffff) \ + XX(15, i, 0xffffff) + +TTYU_INLINE uint32_t util_colormatch(uint8_t i); +TTYU_INLINE int16_t util_rgbi2term(int16_t r, int16_t g, int16_t b); +TTYU_INLINE int16_t util_rgbi2win(int16_t r, int16_t g, int16_t b); +TTYU_INLINE char *util_render(const char *ch, int16_t fg, int16_t bg); +TTYU_INLINE int16_t util_parse_dec(char d); +TTYU_INLINE int16_t util_parse_hex(char h); +TTYU_INLINE uint32_t util_term2argb(int16_t t); +TTYU_INLINE int16_t util_rgb2term(const char *rgb); +TTYU_INLINE int16_t util_hex2term(const char *hex); +TTYU_INLINE int16_t util_color(const char *c); +TTYU_INLINE int util_max(int a, int b); +TTYU_INLINE int util_min(int a, int b); +TTYU_INLINE int util_abs(int a); + +#ifdef DEBUG +# include +# define DBG(msg) std::cout << msg << "\r\n" +#else +# define DBG(msg) // empty +#endif + +#endif // INCLUDE_UTILS_H_ diff --git a/include/win.h b/include/win.h index a61647f..c39a179 100644 --- a/include/win.h +++ b/include/win.h @@ -22,43 +22,101 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ -#ifndef TTYU_WIN_H_ -#define TTYU_WIN_H_ +#ifndef INCLUDE_WIN_H_ +#define INCLUDE_WIN_H_ #include -#define WIN_BUFFER_SIZE 128 +#define PLATFORM_DEPENDENT_FIELDS \ + HANDLE hin; \ + HANDLE hout; \ + DWORD old_mode; \ + uv_mutex_t emitlock; \ + uv_barrier_t barrier; \ + ttyu_worker_c worker -typedef struct ttyu_error_s { - char *msg; - bool kill; -} ttyu_error_t; +class ttyu_worker_c : public NanAsyncWorker { +public: + class ttyu_progress_c { + friend class ttyu_worker_c; + public: + void send(const ttyu_event_t *event) const { + that_->send_(event); + } + private: + explicit ttyu_progress_c(ttyu_worker_c *that) : that_(that) {} + // prevent movement + ttyu_progress_c(const ttyu_progress_c&); + void operator=(const ttyu_progress_c&); +#if __cplusplus >= 201103L + ttyu_progress_c(const ttyu_progress_c&&) V8_DELETE; + void operator=(const ttyu_progress_c&&) V8_DELETE; +#endif + ttyu_worker_c *const that_; + }; -#define ERROR_WIN_INIT "could not get console handles - %d" -#define ERROR_WIN_GET "could not get console output buffer information - %d" -#define ERROR_WIN_SET "could not set console output buffer information - %d" -#define ERROR_WIN_FILL "could not fill console output buffer - %d" + ttyu_worker_c(ttyu_js_c *obj) : NanAsyncWorker(NULL), + asyncdata_(NULL), obj_(obj) { + async = new uv_async_t; + async_lock = new uv_mutex_t; + uv_mutex_init(async_lock); + uv_async_init(uv_default_loop(), async, async_progress_); + async->data = this; + } + ~ttyu_worker_c() { + uv_mutex_destroy(async_lock); + ttyu_event_destroy(asyncdata_); + free(asyncdata_); + } -// windows data structure -struct ttyu_data_s { - HANDLE hin; - HANDLE hout; - DWORD old_mode; - ttyu_error_t *err; - int width; - int height; - int top; - int curx; - int cury; - short base_color; - bool closing; -}; + void progress(); -int ttyu_win_which(DWORD code); -int ttyu_win_ctrl(DWORD state); -DWORD ttyu_win_state(int ctrl); -bool ttyu_win_scr_update(ttyu_data_t *data, bool initial = FALSE); -void ttyu_win_render(char *c, ttyu_data_t *data); -bool ttyu_win_clrscr(ttyu_data_t *data, int x, int y, int width, int height); + bool execute(const ttyu_progress_c& progress, ttyu_js_c *obj); + void handle(ttyu_event_t *event); -#endif // TTYU_WIN_H_ + virtual void Destroy() { + uv_close(reinterpret_cast(async), async_close_); + } + + void Execute() { + ttyu_progress_c progress(this); + uv_barrier_wait(&obj_->barrier); + // loop execute until it returns false (error) + while(execute(progress, obj_)); + } + + void WorkComplete() { + // do nothing + } +private: + void send_(const ttyu_event_t *event) { + ttyu_event_t *new_event = (ttyu_event_t *)malloc(sizeof(event)); + memcpy(&new_event, &event, sizeof(event)); + uv_mutex_lock(async_lock); + ttyu_event_t *old_event = asyncdata_; + asyncdata_ = new_event; + uv_mutex_unlock(async_lock); + + ttyu_event_destroy(old_event); + free(old_event); + uv_async_send(async); + } + + static NAUV_WORK_CB(async_progress_) { + ttyu_worker_c *worker = static_cast(async->data); + worker->progress(); + } + static void async_close_(uv_handle_t *handle) { + ttyu_worker_c *worker = static_cast(handle->data); + delete reinterpret_cast(handle); + delete worker; + } + + + uv_async_t *async; + uv_mutex_t *async_lock; + ttyu_event_t *asyncdata_; + ttyu_js_c *obj_; +} + +#endif // INCLUDE_WIN_H_ diff --git a/package.json b/package.json index 64a687d..23b3fd3 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "cross-platform terminal utilities", "main": "index.js", "scripts": { + "lint": "cpplint.py --extensions=h,cc --filter=-runtime/printf include/* src/*", "test": "./node_modules/.bin/mocha tests/run" }, "repository": { diff --git a/signal.js b/signal.js index 1a26a13..83d52e7 100644 --- a/signal.js +++ b/signal.js @@ -1,33 +1,33 @@ var signal = module.exports = { - on: function(ttyu, that, listener) { - if(!that.__signals__) { - that.__signals__ = {}; - that.__siglisten__ = []; + on: function(ttyu, listener) { + if(!ttyu.__signals__) { + ttyu.__signals__ = {}; + ttyu.__siglisten__ = []; // add signal listeners - for(var sig in ttyu.TTYUtil.SIGNAL) { - process.on(sig, (that.__siglisten__[sig] = - signal.listen(ttyu, sig, that))); + for(var sig in ttyu.SIGNAL) { + process.on(sig, (ttyu.__siglisten__[sig] = + signal.listen(ttyu, sig))); } } - that.__siglisten__.push(listener); + ttyu.__siglisten__.push(listener); }, - off: function(that, listener) { - if(!that.__signals__) return; - var i = that.__siglisten__.indexOf(listener); + off: function(ttyu, listener) { + if(!ttyu.__signals__) return; + var i = ttyu.__siglisten__.indexOf(listener); if(i !== -1) { - that.__siglisten__.splice(i,1); + ttyu.__siglisten__.splice(i,1); } - if(that.__siglisten__.length === 0) { + if(ttyu.__siglisten__.length === 0) { // remove signal listeners - for(var sig in that.__siglisten__) { - process.removeListener(sig, that.__siglisten__[sig]); + for(var sig in ttyu.__siglisten__) { + process.removeListener(sig, ttyu.__siglisten__[sig]); } - that.__signals__ = undefined; - that.__siglisten__ = undefined; + ttyu.__signals__ = undefined; + ttyu.__siglisten__ = undefined; } }, @@ -35,14 +35,14 @@ var signal = module.exports = { process.emit(sig); }, - listen: function(ttyu, sig, that) { + listen: function(ttyu, sig) { return function() { var ev = { - type: ttyu.TTYUtil.EVENT.SIGNAL, + type: ttyu.EVENT.SIGNAL, signal: sig }; - for(var i = 0; i < that.__siglisten__.length; ++i) { - that.__siglisten__[i].call(that, ev); + for(var i = 0; i < ttyu.__siglisten__.length; ++i) { + ttyu.__siglisten__[i].call(ttyu, ev); } }; } diff --git a/src/ttyu.cc b/src/ttyu.cc index 4278b08..4ceac06 100644 --- a/src/ttyu.cc +++ b/src/ttyu.cc @@ -1,4 +1,4 @@ -/* ttyutil - ttyu.cc - implements additional functions +/* ttyutil - ttyu.cc - implements threads and additional functions * https://github.com/clidejs/ttyutil * * Copyright Bernhard Bücherl @@ -29,14 +29,53 @@ int ttyu_ee_cb_call(ee__listener_t *l, v8::Local data) { }; int count = 0; do { - if(l->cb) { + if (l->cb) { l->cb->Call(1, args); ++count; } - } while((l = l->next)); + } while ((l = l->next)); return count; } int ttyu_ee_compare(EE_CB_ARG(cb1), EE_CB_ARG(cb2)) { - return (int)(cb1->GetFunction() == cb2->GetFunction()); + return static_cast(cb1->GetFunction() == cb2->GetFunction()); } + +NAN_METHOD(ttyu_js_c::js_new) { + NanScope(); + ttyu_js_c *obj = new ttyu_js_c(); + obj->Wrap(args.This()); + NanReturnThis(); +} + +// initialize node module +void ttyu_js_c::init(v8::Handle exports, + v8::Handle module) { + v8::Local tpl = + NanNew(js_new); + tpl->SetClassName(NanNew("ttyu_js_c")); + tpl->InstanceTemplate()->SetInternalFieldCount(19); + + EXPORT_METHOD(tpl, "start", js_start); + EXPORT_METHOD(tpl, "stop", js_stop); + EXPORT_METHOD(tpl, "on", js_on); + EXPORT_METHOD(tpl, "off", js_off); + EXPORT_METHOD(tpl, "emit", js_emit); + + EXPORT_METHOD(tpl, "write", js_write); + module->Set(NanNew("exports"), tpl->GetFunction()); +/* + EXPORT_GET(tpl, "running", js_running); + EXPORT_GET(tpl, "width", js_width); + EXPORT_GET(tpl, "height", js_height); + EXPORT_GET(tpl, "mode", js_mode); + EXPORT_GET(tpl, "colors", js_colors); + EXPORT_GETSET(tpl, "x", js_getx, js_setx); + EXPORT_GETSET(tpl, "y", js_gety, js_sety); + EXPORT_METHOD(tpl, "goto", js_goto); + EXPORT_METHOD(tpl, "color", js_color); + EXPORT_METHOD(tpl, "beep", js_beep); + EXPORT_METHOD(tpl, "clear", js_clear); + EXPORT_METHOD(tpl, "prepare", js_prepare);*/ +} +NODE_MODULE(ttyu, ttyu_js_c::init); diff --git a/src/ttyu_event.cc b/src/ttyu_event.cc index 3c56c50..cb2215b 100644 --- a/src/ttyu_event.cc +++ b/src/ttyu_event.cc @@ -39,13 +39,14 @@ void ttyu_event_create_resize(ttyu_event_t *event) { void ttyu_event_create_key(ttyu_event_t *event, int ctrl, char *c, int code, int which) { - char *ch = (char *)std::malloc(sizeof(char) * (strlen(c) + 1)); + char *ch = + reinterpret_cast(std::malloc(sizeof(char) * (strlen(c) + 1))); memcpy(ch, c, sizeof(char) * strlen(c)); ch[strlen(c)] = '\0'; event->type = EVENT_KEY; event->err = NULL; - event->key = (ttyu_key_t *)std::malloc(sizeof(ttyu_key_t)); + event->key = reinterpret_cast(std::malloc(sizeof(ttyu_key_t))); event->mouse = NULL; event->key->ctrl = ctrl; @@ -54,12 +55,13 @@ void ttyu_event_create_key(ttyu_event_t *event, int ctrl, char *c, event->key->which = which; } -void ttyu_event_create_mouse(ttyu_event_t *event, int type, int button, - int x, int y, int ctrl) { +void ttyu_event_create_mouse(ttyu_event_t *event, int type, int button, int x, + int y, int ctrl) { event->type = type; event->err = NULL; event->key = NULL; - event->mouse = (ttyu_mouse_t *)std::malloc(sizeof(ttyu_mouse_t)); + event->mouse = + reinterpret_cast(std::malloc(sizeof(ttyu_mouse_t))); event->mouse->button = button; event->mouse->x = x; @@ -68,12 +70,12 @@ void ttyu_event_create_mouse(ttyu_event_t *event, int type, int button, } void ttyu_event_destroy(ttyu_event_t *event) { - if(event) { - if(event->mouse) { + if (event) { + if (event->mouse) { std::free(event->mouse); } - if(event->key) { - if(event->key->c) { + if (event->key) { + if (event->key->c) { std::free(event->key->c); } std::free(event->mouse); diff --git a/src/ttyu_js.cc b/src/ttyu_js.cc deleted file mode 100644 index f4e1187..0000000 --- a/src/ttyu_js.cc +++ /dev/null @@ -1,161 +0,0 @@ -/* ttyutil - ttyu_js.cc - implements the javascript module - * https://github.com/clidejs/ttyutil - * - * Copyright Bernhard Bücherl - * - * 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. - */ -#include - -v8::Persistent ttyu_js_c::constructor; - -void ttyu_js_c::init(v8::Handle target) { - v8::Local tpl = - NanNew(new_instance); - tpl->SetClassName(NanNew("TTYUtil")); - tpl->InstanceTemplate()->SetInternalFieldCount(19); - - EXPORT_PROTOTYPE_METHOD(tpl, "pause", pause); - EXPORT_PROTOTYPE_METHOD(tpl, "destroy", destroy); - EXPORT_PROTOTYPE_METHOD(tpl, "start", start); - EXPORT_PROTOTYPE_METHOD_HIDDEN(tpl, "__on__", on); - EXPORT_PROTOTYPE_METHOD_HIDDEN(tpl, "__off__", off); - EXPORT_PROTOTYPE_METHOD_HIDDEN(tpl, "__emit__", emit); - EXPORT_PROTOTYPE_GET(tpl, "running", is_running); - - EXPORT_PROTOTYPE_GET(tpl, "width", get_width); - EXPORT_PROTOTYPE_GET(tpl, "height", get_height); - EXPORT_PROTOTYPE_GET(tpl, "mode", get_mode); - EXPORT_PROTOTYPE_GET(tpl, "colors", get_colors); - EXPORT_PROTOTYPE_GETSET(tpl, "x", getx, setx); - EXPORT_PROTOTYPE_GETSET(tpl, "y", gety, sety); - EXPORT_PROTOTYPE_METHOD(tpl, "goto", gotoxy); - EXPORT_PROTOTYPE_METHOD(tpl, "color", color); - EXPORT_PROTOTYPE_METHOD(tpl, "beep", beep); - EXPORT_PROTOTYPE_METHOD(tpl, "clear", clear); - EXPORT_PROTOTYPE_METHOD(tpl, "prepare", prepare); - EXPORT_PROTOTYPE_METHOD(tpl, "write", write); - - NanAssignPersistent(constructor, tpl->GetFunction()); - target->Set(NanNew("TTYUtil"), tpl->GetFunction()); -} - -ttyu_js_c::ttyu_js_c() { - running = FALSE; - paused = FALSE; - destroyed_ = FALSE; - - data = (ttyu_data_t *)malloc(sizeof(ttyu_data_t)); - ttyu_data_init(data); - - emitter = (ee_emitter_t *)malloc(sizeof(ee_emitter_t)); - ee_init(emitter, ttyu_ee_cb_call, ttyu_ee_compare); -} - -ttyu_js_c::~ttyu_js_c() { - destroy(); -} - -void ttyu_js_c::destroy() { - running = FALSE; - paused = FALSE; - destroyed_ = TRUE; - if(data) { - ttyu_data_destroy(data); - free(data); - } -} - -NAN_METHOD(ttyu_js_c::new_instance) { - NanScope(); - ttyu_js_c *obj = new ttyu_js_c(); - obj->throw_ = args[0]->IsBoolean() ? args[1]->BooleanValue() : TRUE; - obj->Wrap(args.This()); - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::start) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_DESTROYED(obj); - if(!obj->running) { - obj->running = TRUE; -#ifndef PLATFORM_WINDOWS -// uv_barrier_init(&(obj->barrier), 2); -#endif - //ttyu_worker_c *w = new ttyu_worker_c(obj); - //NanAsyncQueueWorker(w); - //obj->worker_ = w; - -#ifndef PLATFORM_WINDOWS -// uv_barrier_wait(&(obj->barrier)); -// uv_barrier_destroy(&(obj->barrier)); -#endif - } else if(obj->paused) { - obj->paused = FALSE; - } - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::pause) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_DESTROYED(obj); - if(obj->running && !obj->paused) { - obj->paused = TRUE; - } - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::destroy) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_DESTROYED(obj); - if(obj->running) { - obj->destroy(); - } - NanReturnThis(); -} - -NAN_GETTER(ttyu_js_c::is_running) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(obj->running && !obj->paused)); -} - -NAN_METHOD(ttyu_js_c::on) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_DESTROYED(obj); - ee_on(obj->emitter, args[0]->Int32Value(), - new NanCallback(v8::Local::Cast(args[1]))); - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::off) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_DESTROYED(obj); - ee_off(obj->emitter, args[0]->Int32Value(), - new NanCallback(v8::Local::Cast(args[1]))); - NanReturnThis(); -} - -// export -NODE_MODULE(ttyu, ttyu_js_c::init); diff --git a/src/ttyu_worker.cc b/src/ttyu_worker.cc deleted file mode 100644 index d20a2e6..0000000 --- a/src/ttyu_worker.cc +++ /dev/null @@ -1,159 +0,0 @@ -/* ttyutil - ttyu_worker.cc - implements the background (async) worker - * https://github.com/clidejs/ttyutil - * - * Copyright Bernhard Bücherl - * - * 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. - */ -#include - -void ttyu_worker_c::ttyu_progress_c::send(const ttyu_event_t *event) const { - that_->send_(event); -} - -ttyu_worker_c::ttyu_progress_c::ttyu_progress_c(ttyu_worker_c *that) : - that_(that) {} - -ttyu_worker_c::ttyu_worker_c(ttyu_js_c *obj) : - NanAsyncWorker(NULL), asyncdata_(NULL), obj_(obj) { - async = new uv_async_t; - async_lock = new uv_mutex_t; - uv_mutex_init(async_lock); - uv_async_init(uv_default_loop(), async, async_progress_); - async->data = this; -} - -ttyu_worker_c::~ttyu_worker_c() { - uv_mutex_destroy(async_lock); - ttyu_event_destroy(asyncdata_); - free(asyncdata_); -} - -void ttyu_worker_c::progress() { - uv_mutex_lock(async_lock); - ttyu_event_t *event = asyncdata_; - asyncdata_ = NULL; - uv_mutex_unlock(async_lock); - - if(event) { - handle(event); - } - ttyu_event_destroy(event); - free(event); -} - -void ttyu_worker_c::handle(ttyu_event_t *event) { - if(ee_count(obj_->emitter, event->type) == 0 || obj_->paused || - !obj_->running) { - return; - } - - v8::Local obj = NanNew(); - switch(event->type) { - case EVENT_RESIZE: - obj->Set(NanNew("type"), EVENTSTRING_RESIZE); - break; - case EVENT_KEY: - obj->Set(NanNew("type"), EVENTSTRING_KEY); - obj->Set(NanNew("ctrl"), - NanNew(event->key->ctrl)); - obj->Set(NanNew("char"), NanNew(event->key->c)); - obj->Set(NanNew("code"), - NanNew(event->key->code)); - obj->Set(NanNew("which"), - NanNew(event->key->which)); - break; - case EVENT_MOUSEDOWN: - case EVENT_MOUSEUP: - case EVENT_MOUSEMOVE: - case EVENT_MOUSEWHEEL: - case EVENT_MOUSEHWHEEL: - if(event->type == EVENT_MOUSEDOWN) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEDOWN); - } else if(event->type == EVENT_MOUSEUP) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEUP); - } else if(event->type == EVENT_MOUSEMOVE) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEMOVE); - } else if(event->type == EVENT_MOUSEWHEEL) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEWHEEL); - } else if(event->type == EVENT_MOUSEHWHEEL) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEHWHEEL); - } - obj->Set(NanNew("button"), - NanNew(event->mouse->button)); - obj->Set(NanNew("x"), NanNew(event->mouse->x)); - obj->Set(NanNew("y"), NanNew(event->mouse->y)); - obj->Set(NanNew("ctrl"), - NanNew(event->mouse->ctrl)); - break; - default: // EVENT_ERROR, EVENT_SIGNAL - obj->Set(NanNew("type"), EVENTSTRING_ERROR); - obj->Set(NanNew("error"), NanError(event->err)); - event->type = EVENT_ERROR; - break; - } - ee_emit(obj_->emitter, event->type, obj); -} - -void ttyu_worker_c::Destroy() { - uv_close(reinterpret_cast(async), async_close_); -} - -void ttyu_worker_c::Execute() { - ttyu_progress_c progress(this); -#ifndef PLATFORM_WINDOWS - uv_barrier_wait(&(obj_->barrier)); -#endif - // loop execute until it returns false (error) - while(execute(progress, obj_->data)); -} - -void ttyu_worker_c::send_(const ttyu_event_t *event) { - ttyu_event_t *new_event = (ttyu_event_t *)malloc(sizeof(event)); - memcpy(&new_event, &event, sizeof(event)); - uv_mutex_lock(async_lock); - ttyu_event_t *old_event = asyncdata_; - asyncdata_ = new_event; - uv_mutex_unlock(async_lock); - - ttyu_event_destroy(old_event); - free(old_event); - uv_async_send(async); -} - -NAUV_WORK_CB(ttyu_worker_c::async_progress_) { - ttyu_worker_c *worker = static_cast(async->data); - worker->progress(); -} - -void ttyu_worker_c::async_close_(uv_handle_t *handle) { - ttyu_worker_c *worker = static_cast(handle->data); - delete reinterpret_cast(handle); - - if(worker->obj_->emitter) { - ee_destroy(worker->obj_->emitter); - delete worker->obj_->emitter; - } - - delete worker; -} - -void ttyu_worker_c::WorkComplete() { - // do nothing -} diff --git a/src/unix.cc b/src/unix.cc index fd44755..c8a70ab 100644 --- a/src/unix.cc +++ b/src/unix.cc @@ -23,405 +23,338 @@ */ #include -void ttyu_data_init(ttyu_data_t *data) { - data->win = initscr(); - data->closing = FALSE; - data->mode = MODE_VT100; +ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), mode(MODE_VT100) { + ee_init(&emitter, ttyu_ee_cb_call, ttyu_ee_compare); +} + +ttyu_js_c::~ttyu_js_c() { + running = FALSE; + stop = TRUE; + ee_destroy(&emitter); +} -// data->ungetch_stack = new std::queue< int, std::list >; -// data->ungetmouse_stack = new std::queue< MEVENT, std::list >; +NAN_METHOD(ttyu_js_c::js_start) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + obj->running = TRUE; + obj->stop = FALSE; + obj->win = initscr(); noecho(); cbreak(); - keypad(data->win, TRUE); - mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, &(data->old_mouse_mask)); + keypad(obj->win, TRUE); + mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); + nodelay(obj->win, 0); mouseinterval(0); - nodelay(data->win, TRUE); + + uv_barrier_init(&obj->barrier, 2); + uv_mutex_init(&obj->emitlock); + uv_mutex_init(&obj->ungetlock); + + uv_thread_create(&obj->curses_thread, ttyu_js_c::curses_thread_func, obj); + + NAUV_BARRIER_WAIT(&obj->barrier, TRUE); + + NanReturnThis(); } -void ttyu_data_destroy(ttyu_data_t *data) { - data->closing = TRUE; - echo(); - while(!data->ungetch_stack.empty()) data->ungetch_stack.pop(); - while(!data->ungetmouse_stack.empty()) data->ungetmouse_stack.pop(); - data->ungetch_stack.push(TTYU_EXIT); - endwin(); +NAN_METHOD(ttyu_js_c::js_stop) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + obj->running = FALSE; + obj->stop = TRUE; + uv_thread_join(&obj->curses_thread); + uv_mutex_destroy(&obj->emitlock); + uv_mutex_destroy(&obj->ungetlock); + NanReturnThis(); } -bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, - ttyu_data_t *data) { - int c = getch(); +NAN_METHOD(ttyu_js_c::js_on) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + uv_mutex_lock(&obj->emitlock); + ee_on(&obj->emitter, args[0]->Int32Value(), + new NanCallback(v8::Local::Cast(args[1]))); + uv_mutex_unlock(&obj->emitlock); + NanReturnThis(); +} - if(c == TTYU_EXIT) { return FALSE; } - if(data->closing) { return FALSE; } +NAN_METHOD(ttyu_js_c::js_off) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + uv_mutex_lock(&obj->emitlock); + ee_off(&obj->emitter, args[0]->Int32Value(), + new NanCallback(v8::Local::Cast(args[1]))); + uv_mutex_unlock(&obj->emitlock); + NanReturnThis(); +} + +NAN_METHOD(ttyu_js_c::js_emit) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + int arg0 = args[0]->Int32Value(); + int arg1 = args[1]->Int32Value(); + int arg2 = args[2]->Int32Value(); + int arg3 = args[3]->Int32Value(); + int arg4 = args[4]->Int32Value(); + ttyu_event_t event; + switch (arg0) { + case EVENT_KEY: { + int c = -1; + if (arg2 & CTRL_CMD) { + c = KEY_COMMAND; + } else if (arg1 >= 65 && arg1 <= 90) { + if (arg2 & CTRL_SHIFT) { + c = arg1; // A-Z + } else { + c = arg1 + 32; // a-z + } + } else if (arg1 >= 48 && arg1 <= 57) { + c = arg1; // 0 - 9 + } else { + c = ttyu_unix_key(arg1); + } // TODO(@bbuecherl) v + ttyu_event_create_key(&event, arg2, " ", c, arg1); + } break; + case EVENT_MOUSEDOWN: + case EVENT_MOUSEUP: + case EVENT_MOUSEMOVE: { + ttyu_event_create_mouse(&event, arg0, arg1, arg2, arg3, arg4); + } break; + default: + // EVENT_NONE, EVENT_ERROR, EVENT_SIGNAL, EVENT_RESIZE, EVENT_MOUSEWHEEL, + // EVENT_MOUSEHWHEEL + event.type = EVENT_NONE; + break; + } + + if (event.type == EVENT_NONE) { + uv_mutex_lock(&obj->ungetlock); + obj->unget_stack.push_back(&event); + uv_mutex_unlock(&obj->ungetlock); + } + NanReturnThis(); +} + +NAN_METHOD(ttyu_js_c::js_write) { + NanScope(); + NanReturnThis(); +} - if(c == ERR) { - if(data->ungetch_stack.empty()) { - if(!(data->ungetmouse_stack.empty())) { - // work on mouse stack - //ungetmouse(&(data->ungetmouse_stack->pop())); +void ttyu_js_c::handle(uv_work_t *req) { + DBG("handle"); +} + +void ttyu_js_c::complete(uv_work_t *req) { + NanScope(); + DBG("completed"); + ttyu_work_t *work = static_cast(req->data); + if (ee_count(&work->data->emitter, work->event->type) == 0 || + work->event->type == EVENT_NONE) { + return; + } + + v8::Local obj = NanNew(); + switch (work->event->type) { + case EVENT_RESIZE: + obj->Set(NanNew("type"), EVENTSTRING_RESIZE); + break; + case EVENT_KEY: + obj->Set(NanNew("type"), EVENTSTRING_KEY); + obj->Set(NanNew("ctrl"), + NanNew(work->event->key->ctrl)); + obj->Set(NanNew("char"), + NanNew(work->event->key->c)); + obj->Set(NanNew("code"), + NanNew(work->event->key->code)); + obj->Set(NanNew("which"), + NanNew(work->event->key->which)); + break; + case EVENT_MOUSEDOWN: + case EVENT_MOUSEUP: + case EVENT_MOUSEMOVE: + case EVENT_MOUSEWHEEL: + case EVENT_MOUSEHWHEEL: + if (work->event->type == EVENT_MOUSEDOWN) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEDOWN); + } else if (work->event->type == EVENT_MOUSEUP) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEUP); + } else if (work->event->type == EVENT_MOUSEMOVE) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEMOVE); + } else if (work->event->type == EVENT_MOUSEWHEEL) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEWHEEL); + } else if (work->event->type == EVENT_MOUSEHWHEEL) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEHWHEEL); } - } else { - // work on the char stack - c = *data->ungetch_stack.pop(); - ungetch(c == -1 ? TTYU_UNKNOWN : c); - } - return TRUE; + obj->Set(NanNew("button"), + NanNew(work->event->mouse->button)); + obj->Set(NanNew("x"), + NanNew(work->event->mouse->x)); + obj->Set(NanNew("y"), + NanNew(work->event->mouse->y)); + obj->Set(NanNew("ctrl"), + NanNew(work->event->mouse->ctrl)); + break; + default: // EVENT_ERROR, EVENT_SIGNAL + obj->Set(NanNew("type"), EVENTSTRING_ERROR); + obj->Set(NanNew("error"), NanError(work->event->err)); + work->event->type = EVENT_ERROR; + break; } + uv_mutex_lock(&work->data->emitlock); + ee_emit(&work->data->emitter, work->event->type, obj); + uv_mutex_unlock(&work->data->emitlock); +} + +int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { + ttyu_js_c *obj = static_cast(that); + int c = wgetch(win); MEVENT mev; - ttyu_event_t *event = (ttyu_event_t *)malloc(sizeof(ttyu_event_t)); + ttyu_event_t event; + event.type = EVENT_NONE; + + if (c == ERR) { + uv_mutex_lock(&obj->ungetlock); + if (obj->unget_stack.size() > 0) { + // TODO(@bbuecherl) work on the stack + uv_mutex_unlock(&obj->ungetlock); + } else { + uv_mutex_unlock(&obj->ungetlock); + return 0; // fast exit + } + } - if(c == KEY_RESIZE) { - ttyu_event_create_resize(event); - progress.send(const_cast(event)); - } else if(c == KEY_MOUSE) { - if(getmouse(&mev) == OK) { - ttyu_event_create_mouse(event, EVENT_ERROR, 0, mev.x, mev.y, 0); + if (c == KEY_RESIZE) { + ttyu_event_create_resize(&event); + } else if (c == KEY_MOUSE) { + if (getmouse(&mev) == OK) { + ttyu_event_create_mouse(&event, EVENT_ERROR, 0, mev.x, mev.y, 0); // add button control key sequences if possible - if(mev.bstate & BUTTON_SHIFT) { event->mouse->ctrl |= CTRL_SHIFT; } - if(mev.bstate & BUTTON_CTRL) { event->mouse->ctrl |= CTRL_CTRL; } - if(mev.bstate & BUTTON_ALT) { event->mouse->ctrl |= CTRL_ALT; } + if (mev.bstate & BUTTON_SHIFT) { event.mouse->ctrl |= CTRL_SHIFT; } + if (mev.bstate & BUTTON_CTRL) { event.mouse->ctrl |= CTRL_CTRL; } + if (mev.bstate & BUTTON_ALT) { event.mouse->ctrl |= CTRL_ALT; } // convert button codes and mev type - if(mev.bstate & REPORT_MOUSE_POSITION) { - event->type = EVENT_MOUSEMOVE; - - } else if(mev.bstate & BUTTON1_RELEASED) { - event->mouse->button = MOUSE_LEFT; - event->type = EVENT_MOUSEUP; - } else if(mev.bstate & BUTTON1_PRESSED) { - event->mouse->button = MOUSE_LEFT; - event->type = EVENT_MOUSEDOWN; - - } else if(mev.bstate & BUTTON2_RELEASED) { - event->mouse->button = MOUSE_LEFT2; - event->type = EVENT_MOUSEUP; - } else if(mev.bstate & BUTTON2_PRESSED) { - event->mouse->button = MOUSE_LEFT2; - event->type = EVENT_MOUSEDOWN; - - } else if(mev.bstate & BUTTON3_RELEASED) { - event->mouse->button = MOUSE_LEFT3; - event->type = EVENT_MOUSEUP; - } else if(mev.bstate & BUTTON3_PRESSED) { - event->mouse->button = MOUSE_LEFT3; - event->type = EVENT_MOUSEDOWN; - } else + if (mev.bstate & REPORT_MOUSE_POSITION) { + event.type = EVENT_MOUSEMOVE; + } else if (mev.bstate & BUTTON1_RELEASED) { + event.mouse->button = MOUSE_LEFT; + event.type = EVENT_MOUSEUP; + } else if (mev.bstate & BUTTON1_PRESSED) { + event.mouse->button = MOUSE_LEFT; + event.type = EVENT_MOUSEDOWN; + } else if (mev.bstate & BUTTON2_RELEASED) { + event.mouse->button = MOUSE_LEFT2; + event.type = EVENT_MOUSEUP; + } else if (mev.bstate & BUTTON2_PRESSED) { + event.mouse->button = MOUSE_LEFT2; + event.type = EVENT_MOUSEDOWN; + } else if (mev.bstate & BUTTON3_RELEASED) { + event.mouse->button = MOUSE_LEFT3; + event.type = EVENT_MOUSEUP; + } else if (mev.bstate & BUTTON3_PRESSED) { + event.mouse->button = MOUSE_LEFT3; + event.type = EVENT_MOUSEDOWN; + } else { #if NCURSES_MOUSE_VERSION > 1 - if(mev.bstate & BUTTON4_RELEASED) { - event->mouse->button = MOUSE_LEFT4; - event->type = EVENT_MOUSEUP; - } else if(mev.bstate & BUTTON4_PRESSED) { - event->mouse->button = MOUSE_LEFT4; - event->type = EVENT_MOUSEDOWN; - - } else if(mev.bstate & BUTTON5_RELEASED) { - event->mouse->button = MOUSE_RIGHT; - event->type = EVENT_MOUSEUP; - } else if(mev.bstate & BUTTON5_PRESSED) { - event->mouse->button = MOUSE_RIGHT; - event->type = EVENT_MOUSEDOWN; - } + if (mev.bstate & BUTTON4_RELEASED) { + event.mouse->button = MOUSE_LEFT4; + event.type = EVENT_MOUSEUP; + } else if (mev.bstate & BUTTON4_PRESSED) { + event.mouse->button = MOUSE_LEFT4; + event.type = EVENT_MOUSEDOWN; + } else if (mev.bstate & BUTTON5_RELEASED) { + event.mouse->button = MOUSE_RIGHT; + event.type = EVENT_MOUSEUP; + } else if (mev.bstate & BUTTON5_PRESSED) { + event.mouse->button = MOUSE_RIGHT; + event.type = EVENT_MOUSEDOWN; + } #else - if(mev.bstate & BUTTON4_RELEASED) { - event->mouse->button = MOUSE_RIGHT; - event->type = EVENT_MOUSEUP; - } else if(mev.bstate & BUTTON4_PRESSED) { - event->mouse->button = MOUSE_RIGHT; - event->type = EVENT_MOUSEDOWN; - } + if (mev.bstate & BUTTON4_RELEASED) { + event.mouse->button = MOUSE_RIGHT; + event.type = EVENT_MOUSEUP; + } else if (mev.bstate & BUTTON4_PRESSED) { + event.mouse->button = MOUSE_RIGHT; + event.type = EVENT_MOUSEDOWN; + } #endif - if(event->type == EVENT_ERROR) { + } + if (event.type == EVENT_ERROR) { // uncaught mouse event - ttyu_event_destroy(event); - ttyu_event_create_error(event, ERROR_UNIX_MOUSEUNCAUGHT); + event.type = EVENT_NONE; } else { - // its VT102 - data->mode = MODE_VT102; + obj->mode = MODE_VT102; } } else { // bad mouse event - ttyu_event_create_error(event, ERROR_UNIX_MOUSEBAD); + event.type = EVENT_NONE; } - progress.send(const_cast(event)); } else { char *ch = const_cast(keyname(c)); int ctrl = CTRL_NULL; int which = WHICH_UNKNOWN; - if(c >= 48 && c <= 57) { - which = c; // WHICH_CHAR0 to WHICH_CHAR9 - } else if(c >= 65 && c <= 90) { + if (c >= 48 && c <= 57) { + which = c; // WHICH_CHAR0 to WHICH_CHAR9 + } else if (c >= 65 && c <= 90) { ctrl |= CTRL_SHIFT; - which = c; // WHICH_CHARA to WHICH_CHARZ - } else if(c >= 97 && c <= 122) { - which = c - 32; // WHICH_CHARA to WHICH_CHARZ - } else if(c == KEY_COMMAND) { + which = c; // WHICH_CHARA to WHICH_CHARZ + } else if (c >= 97 && c <= 122) { + which = c - 32; // WHICH_CHARA to WHICH_CHARZ + } else if (c == KEY_COMMAND) { ctrl |= CTRL_CMD; - } else if(c == KEY_SCOMMAND) { + } else if (c == KEY_SCOMMAND) { ctrl |= CTRL_CMD | CTRL_SHIFT; } else { which = ttyu_unix_which(c); - //if(ch[0] == '^') { + // if (ch[0] == '^') { // ctrl |= CTRL_CTRL; - //} + // } } + ttyu_event_create_key(&event, ctrl, ch, c, which); + } - ttyu_event_create_key(event, ctrl, ch, c, which); - progress.send(const_cast(event)); + if (event.type != EVENT_NONE) { + /* + uv_work_t work; + ttyu_work_t w; + w.event = &event; + w.data = obj; + work.data = &w; + uv_queue_work(uv_default_loop(), &work, handle, (uv_after_work_cb)complete); + */ } - return TRUE; + return 0; } -void ttyu_unix_clrscr(ttyu_data_t *data, int x, int y, int width, int height) { - if(x == 0 && y == 0 && width == COLS && height == LINES) { - wclear(data->win); - } else if(width != 0 || height != 0 || x < COLS || y < LINES) { - int ox = data->win->_curx; - int oy = data->win->_cury; - wmove(data->win, x, y); +void ttyu_js_c::curses_thread_func(void *that) { + ttyu_js_c *obj = static_cast(that); + NAUV_BARRIER_WAIT(&obj->barrier, FALSE); - for(int j = 0; j < height; ++j) { - for(int i = 0; i < width; ++i) { - std::cout << " "; - } - std::cout << "\r\n"; - } - wmove(data->win, ox, oy); + while (obj->running && !obj->stop) { + use_window(obj->win, curses_threaded_func, that); + usleep(100); } + endwin(); } -int ttyu_unix_key(int which) { - #define XXKEY(w, key, shift) if(w == which) { \ +TTYU_INLINE int ttyu_unix_key(int which) { + #define XXKEY(w, key, shift) if (w == which) { \ return key; \ } TTYU_UNIX_KW(XXKEY); + #undef XXKEY return WHICH_UNKNOWN; } -int ttyu_unix_which(int key) { - #define XXWHICH(which, k, shift) if(k == key) { \ +TTYU_INLINE int ttyu_unix_which(int key) { + #define XXWHICH(which, k, shift) if (k == key) { \ return which; \ } TTYU_UNIX_KW(XXWHICH); + #undef XXWHICH return WHICH_UNKNOWN; } - -NAN_METHOD(ttyu_js_c::emit) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - if(obj->running) { - int ev = args[0]->Int32Value(); - - switch(ev) { - case EVENT_KEY: { - int c = -1; - int which = args[1]->Int32Value(); - int ctrl = args[2]->Int32Value(); - if(ctrl & CTRL_CMD) { - c = KEY_COMMAND; - } else if(which >= 65 && which <= 90) { - if(ctrl & CTRL_SHIFT) { - c = which; // A-Z - } else { - c = which + 32; // a-z - } - } else if(which >= 48 && which <= 57) { - c = which; // 0 - 9 - } else { - c = ttyu_unix_key(which); - } - obj->data->ungetch_stack.push(c); - } break; - case EVENT_MOUSEDOWN: - case EVENT_MOUSEUP: - case EVENT_MOUSEMOVE: { - MEVENT mev; - int b = args[1]->Int32Value(); - int ctrl = args[4]->Int32Value(); - - mev.x = (short)args[2]->Int32Value(); - mev.y = (short)args[3]->Int32Value(); - mev.bstate = 0; - - if(ctrl & CTRL_ALT) { mev.bstate |= BUTTON_ALT; } - if(ctrl & CTRL_CTRL) { mev.bstate |= BUTTON_CTRL; } - if(ctrl & CTRL_SHIFT) { mev.bstate |= BUTTON_SHIFT; } - - if(ev == EVENT_MOUSEMOVE) { - mev.bstate |= REPORT_MOUSE_POSITION; - } else if(ev == EVENT_MOUSEUP) { - if(b == MOUSE_LEFT) { - mev.bstate |= BUTTON1_RELEASED; - } else if(b == MOUSE_LEFT2) { - mev.bstate |= BUTTON2_RELEASED; - } else if(b == MOUSE_LEFT3) { - mev.bstate |= BUTTON3_RELEASED; - } else if(b == MOUSE_LEFT4) { - mev.bstate |= BUTTON4_RELEASED; - } else if(b == MOUSE_RIGHT) { -#if NCURSES_MOUSE_VERSION > 1 - mev.bstate |= BUTTON5_RELEASED; -#else - mev.bstate |= BUTTON4_RELEASED; -#endif - } - } else if(ev == EVENT_MOUSEDOWN) { - if(b == MOUSE_LEFT) { - mev.bstate |= BUTTON1_PRESSED; - } else if(b == MOUSE_LEFT2) { - mev.bstate |= BUTTON2_PRESSED; - } else if(b == MOUSE_LEFT3) { - mev.bstate |= BUTTON3_PRESSED; - } else if(b == MOUSE_LEFT4) { - mev.bstate |= BUTTON4_PRESSED; - } else if(b == MOUSE_RIGHT) { -#if NCURSES_MOUSE_VERSION > 1 - mev.bstate |= BUTTON5_PRESSED; -#else - mev.bstate |= BUTTON4_PRESSED; -#endif - } - } - - obj->data->ungetmouse_stack.push(mev); - } break; - default: // EVENT_ERROR, EVENT_SIGNAL, EVENT_RESIZE, EVENT_MOUSEWHEEL, - // EVENT_MOUSEHWHEEL - // do nothing - break; - } - } - NanReturnUndefined(); -} - -NAN_GETTER(ttyu_js_c::get_width) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - NanReturnValue(NanNew(COLS)); -} - -NAN_GETTER(ttyu_js_c::get_height) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - NanReturnValue(NanNew(LINES)); -} - -NAN_GETTER(ttyu_js_c::get_mode) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - NanReturnValue(NanNew(obj->data->mode)); -} - -NAN_GETTER(ttyu_js_c::get_colors) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - NanReturnValue(NanNew(COLORS)); -} - -NAN_GETTER(ttyu_js_c::getx) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - NanReturnValue(NanNew(obj->data->win->_curx)); -} - -NAN_SETTER(ttyu_js_c::setx) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING_VOID(obj); - obj->data->win->_curx = args.Data()->Int32Value(); -} - -NAN_GETTER(ttyu_js_c::gety) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - NanReturnValue(NanNew(obj->data->win->_cury)); -} - -NAN_SETTER(ttyu_js_c::sety) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING_VOID(obj); - obj->data->win->_cury = args.Data()->Int32Value(); -} - -NAN_METHOD(ttyu_js_c::gotoxy) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - wmove(obj->data->win, args[1]->Int32Value(), args[0]->Int32Value()); - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::write) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - v8::String::Utf8Value *ch = new v8::String::Utf8Value(args[0]->ToString()); - int fg = args[1]->IsNumber() ? args[1]->Int32Value() : ( - args[1]->IsString() ? util_color( - (new v8::String::Utf8Value(args[1]->ToString()))->operator*()) : - 1); - int bg = args[2]->IsNumber() ? args[2]->Int32Value() : ( - args[2]->IsString() ? util_color( - (new v8::String::Utf8Value(args[2]->ToString()))->operator*()) : - 1); - printf("%s", util_render(ch->operator*(), fg, bg)); - refresh(); - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::beep) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - ::beep(); - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::clear) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - - if(args[0]->IsNumber() && args[1]->IsNumber() && args[2]->IsNumber() && - args[3]->IsNumber()) { - ttyu_unix_clrscr(obj->data, - util_max(args[0]->Int32Value(), 0), // x - util_max(args[1]->Int32Value(), 0), // y - util_min(args[2]->Int32Value(), COLS), // width - util_min(args[3]->Int32Value(), LINES));// height - } else { - ttyu_unix_clrscr(obj->data, 0, 0, COLS, LINES); - } - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::prepare) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - v8::String::Utf8Value *ch = new v8::String::Utf8Value(args[0]->ToString()); - int fg = args[1]->IsNumber() ? args[1]->Int32Value() : ( - args[1]->IsString() ? util_color( - (new v8::String::Utf8Value(args[1]->ToString()))->operator*()) : - 1); - int bg = args[2]->IsNumber() ? args[2]->Int32Value() : ( - args[2]->IsString() ? util_color( - (new v8::String::Utf8Value(args[2]->ToString()))->operator*()) : - 1); - NanReturnValue(NanNew(util_render(ch->operator*(), fg, bg))); -} - -NAN_METHOD(ttyu_js_c::color) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - v8::String::Utf8Value *ch = new v8::String::Utf8Value(args[0]->ToString()); - NanReturnValue(NanNew(util_color(ch->operator*()))); -} diff --git a/src/util.cc b/src/utils.cc similarity index 62% rename from src/util.cc rename to src/utils.cc index 3f5cc2f..b2325e2 100644 --- a/src/util.cc +++ b/src/utils.cc @@ -23,46 +23,34 @@ */ #include -unsigned long util_colors_a[] = { - 0x000000, - 0x800000, - 0x008000, - 0x808000, - 0x000080, - 0x800080, - 0x008080, - 0xc0c0c0, - 0x808080, - 0xff0000, - 0x00ff00, - 0xffff00, - 0x0000ff, - 0xff00ff, - 0x00ffff, - 0xffffff -}; - -short util_rgbi2term(short r, short g, short b) { - return (short)(r / 51 * 36 + g / 51 * 6 + b / 51 + 16); +TTYU_INLINE uint32_t util_colormatch(uint8_t i) { + #define XX(index, i, c) if (index == i) { return c; } + COLORS_ARRAY(XX, i); + #undef XX + return 0; +} + +TTYU_INLINE int16_t util_rgbi2term(int16_t r, int16_t g, int16_t b) { + return static_cast(r / 51 * 36 + g / 51 * 6 + b / 51 + 16); } -short util_rgbi2win(short r, short g, short b) { - unsigned long match; - short match_i = 0; +TTYU_INLINE int16_t util_rgbi2win(int16_t r, int16_t g, int16_t b) { + uint32_t match; + int16_t match_i = 0; int match_diff = 256+256+256; int diff; unsigned char mr; unsigned char mg; unsigned char mb; - for(short i = 0; i < 16; ++i) { - match = util_colors_a[i]; + for (uint8_t i = 0; i < 16; ++i) { + match = util_colormatch(i); mb = ((match << 8) >> 24); mg = ((match << 16) >> 24); mr = ((match << 24) >> 24); diff = util_abs(mr - r) + util_abs(mg - g) + util_abs(mb - b); - if(diff <= match_diff) { + if (diff <= match_diff) { match_diff = diff; match_i = i; } @@ -70,13 +58,14 @@ short util_rgbi2win(short r, short g, short b) { return match_i; } -char *util_render(const char *ch, short fg, short bg) { - char *out = (char *)malloc(sizeof(char) * (strlen(ch) + 30)); - if(fg != -1 && bg != -1) { +TTYU_INLINE char *util_render(const char *ch, int16_t fg, int16_t bg) { + char *out = + reinterpret_cast(std::malloc(sizeof(char) * (strlen(ch) + 30))); + if (fg != -1 && bg != -1) { sprintf(out, "\x1b[38;5;%dm\x1b[48;5;%dm%s\x1b[49m\x1b[39m", fg, bg, ch); - } else if(fg != -1) { + } else if (fg != -1) { sprintf(out, "\x1b[38;5;%dm%s\x1b[39m", fg, ch); - } else if(bg != -1) { + } else if (bg != -1) { sprintf(out, "\x1b[48;5;%dm%s\x1b[49m", bg, ch); } else { sprintf(out, "%s", ch); @@ -84,24 +73,24 @@ char *util_render(const char *ch, short fg, short bg) { return out; } -short util_parse_dec(char d) { - if(d >= '0' && d <= '9') { +TTYU_INLINE int16_t util_parse_dec(char d) { + if (d >= '0' && d <= '9') { return d - '0'; } return 0; } -short util_parse_hex(char h) { - if(h >= 'A' && h <= 'F') { +TTYU_INLINE int16_t util_parse_hex(char h) { + if (h >= 'A' && h <= 'F') { return h - 'A' + 10; - } else if(h >= 'a' && h <= 'f') { + } else if (h >= 'a' && h <= 'f') { return h - 'a' + 10; } return util_parse_dec(h); } -unsigned long util_term2argb(short t) { - unsigned long argb = 0; +TTYU_INLINE uint32_t util_term2argb(int16_t t) { + uint32_t argb = 0; t -= 16; argb = ((t / 36) * 51) << 8; argb += ((t % 36)/ 6) * 51; @@ -110,23 +99,23 @@ unsigned long util_term2argb(short t) { return argb; } -short util_rgb2term(const char *rgb) { - short r = 0; - short g = 0; - short b = 0; - short cur = 0; - short pos = 0; +TTYU_INLINE int16_t util_rgb2term(const char *rgb) { + int16_t r = 0; + int16_t g = 0; + int16_t b = 0; + int16_t cur = 0; + int16_t pos = 0; - for(int i = (int)strlen(rgb); i >= 0; --i) { - if(rgb[i] == ',') { + for (uint8_t i = static_cast(strlen(rgb)); i >= 0; --i) { + if (rgb[i] == ',') { ++cur; pos = 0; - } else if(rgb[i] != ')') { - if(cur == 0) { + } else if (rgb[i] != ')') { + if (cur == 0) { b += util_parse_dec(rgb[i]) * (pos == 2 ? 100 : (pos == 1 ? 10 : 1)); - } else if(cur == 1) { + } else if (cur == 1) { g += util_parse_dec(rgb[i]) * (pos == 2 ? 100 : (pos == 1 ? 10 : 1)); - } else if(cur == 2) { + } else if (cur == 2) { r += util_parse_dec(rgb[i]) * (pos == 2 ? 100 : (pos == 1 ? 10 : 1)); } ++pos; @@ -139,15 +128,15 @@ short util_rgb2term(const char *rgb) { #endif } -short util_hex2term(const char *hex) { - short r = 0; - short g = 0; - short b = 0; - if(strlen(hex) == 6) { +TTYU_INLINE int16_t util_hex2term(const char *hex) { + int16_t r = 0; + int16_t g = 0; + int16_t b = 0; + if (strlen(hex) == 6) { r = util_parse_hex(hex[0]) * 16 + util_parse_hex(hex[1]); g = util_parse_hex(hex[2]) * 16 + util_parse_hex(hex[3]); b = util_parse_hex(hex[4]) * 16 + util_parse_hex(hex[5]); - } else if(strlen(hex) == 3) { + } else if (strlen(hex) == 3) { r = util_parse_hex(hex[0]); g = util_parse_hex(hex[1]); b = util_parse_hex(hex[2]); @@ -162,30 +151,24 @@ short util_hex2term(const char *hex) { #endif } -short util_color(const char *c) { - if(c[0] == '#') { +TTYU_INLINE int16_t util_color(const char *c) { + if (c[0] == '#') { return util_hex2term(&c[1]); - } else if(c[0] == 'r' && c[1] == 'g' && c[2] == 'b' && c[3] == '(') { + } else if (c[0] == 'r' && c[1] == 'g' && c[2] == 'b' && c[3] == '(') { return util_rgb2term(&c[4]); } else { return util_hex2term(c); } } -int util_max(int a, int b) { - return (a>b)?a:b; +TTYU_INLINE int util_max(int a, int b) { + return (a > b) ? a : b; } -int util_min(int a, int b) { - return (a>b)?b:a; +TTYU_INLINE int util_min(int a, int b) { + return (a > b) ? b : a; } -int util_abs(int a) { - return (a<0)?a*-1:a; -} - -char *util_error(char *name, int id) { - char *out = (char *)malloc(sizeof(char) * (strlen(name) + 5)); - sprintf(out, name, id); - return out; +TTYU_INLINE int util_abs(int a) { + return (a < 0) ? a * -1 : a; } diff --git a/src/win.cc b/src/win.cc index 6f3d8c3..08c2434 100644 --- a/src/win.cc +++ b/src/win.cc @@ -23,528 +23,75 @@ */ #include -void ttyu_data_init(ttyu_data_t *data) { - DWORD new_mode; - - data->err = (ttyu_error_t *)malloc(sizeof(ttyu_error_t)); - data->hin = GetStdHandle(STD_INPUT_HANDLE); - data->hout = GetStdHandle(STD_OUTPUT_HANDLE); - data->closing = false; - - if(INVALID_HANDLE_VALUE == data->hin || INVALID_HANDLE_VALUE == data->hout) { - data->err->msg = ERROR(ERROR_WIN_INIT, GetLastError()); - data->err->kill = TRUE; - return; - } - data->err->msg = NULL; - data->err->kill = FALSE; - - GetConsoleMode(data->hin, &(data->old_mode)); - new_mode = ((data->old_mode | ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS | - ENABLE_PROCESSED_INPUT | ENABLE_WINDOW_INPUT) & - ~(ENABLE_QUICK_EDIT_MODE)); - SetConsoleMode(data->hin, new_mode); - - ttyu_win_scr_update(data, TRUE); -} - -void ttyu_data_destroy(ttyu_data_t *data) { - data->closing = true; - DWORD w; - INPUT_RECORD in; - in.EventType = MENU_EVENT; - WriteConsoleInput(data->hin, const_cast(&in), 1, &w); - SetConsoleMode(data->hin, data->old_mode); -} - -bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, - ttyu_data_t *data) { - DWORD readed; - INPUT_RECORD ir[WIN_BUFFER_SIZE]; - DWORD i; - - if(data->err->msg) { - ttyu_event_t *event = (ttyu_event_t *)malloc(sizeof(ttyu_event_t)); - ttyu_event_create_error(event, data->err->msg); - progress.send(const_cast(event)); - if(data->err->kill) { - return FALSE; - } - data->err->msg = NULL; - data->err->kill = FALSE; - } - - ReadConsoleInput(data->hin, ir, WIN_BUFFER_SIZE, &readed); - // exit - if(data->closing) { return FALSE; } - - for(i = 0; i < readed; ++i) { - if(MOUSE_EVENT == ir[i].EventType) { - ttyu_event_t *event = (ttyu_event_t *)malloc(sizeof(ttyu_event_t)); - ttyu_event_create_mouse(event, EVENT_ERROR, - (int)ir[i].Event.MouseEvent.dwButtonState, - (int)ir[i].Event.MouseEvent.dwMousePosition.X, - (int)ir[i].Event.MouseEvent.dwMousePosition.Y - data->top, - ttyu_win_ctrl(ir[i].Event.MouseEvent.dwControlKeyState)); - - if(ir[i].Event.MouseEvent.dwButtonState == 0 && - ir[i].Event.MouseEvent.dwEventFlags == 0) { - event->type = EVENT_MOUSEUP; - } else if(ir[i].Event.MouseEvent.dwEventFlags == 0 || - ir[i].Event.MouseEvent.dwEventFlags == 2) { - event->type = EVENT_MOUSEDOWN; - } else if(ir[i].Event.MouseEvent.dwEventFlags == 1) { - event->type = EVENT_MOUSEMOVE; - } else if(ir[i].Event.MouseEvent.dwEventFlags == 4) { - event->type = EVENT_MOUSEWHEEL; - } else if(ir[i].Event.MouseEvent.dwEventFlags == 8) { - event->type = EVENT_MOUSEHWHEEL; - } - - progress.send(const_cast(event)); - } else if(KEY_EVENT == ir[i].EventType && ir[i].Event.KeyEvent.bKeyDown) { - ttyu_event_t *event = (ttyu_event_t *)malloc(sizeof(ttyu_event_t)); - char *ch = (char *)std::malloc(sizeof(char) * 3); - memcpy(ch, &(ir[i].Event.KeyEvent.uChar.UnicodeChar), sizeof(char) * 2); - ch[2] = '\0'; - - ttyu_event_create_key(event, ttyu_win_ctrl( - ir[i].Event.KeyEvent.dwControlKeyState), ch, - (int)ir[i].Event.KeyEvent.wVirtualKeyCode, - ttyu_win_which(ir[i].Event.KeyEvent.wVirtualKeyCode)); - - free(ch); - - progress.send(const_cast(event)); - } else if(WINDOW_BUFFER_SIZE_EVENT == ir[i].EventType) { - ttyu_event_t *event = (ttyu_event_t *)malloc(sizeof(ttyu_event_t)); - - if(!ttyu_win_scr_update(data)) { - ttyu_event_create_error(event, data->err->msg); - } else { - ttyu_event_create_resize(event); - } - progress.send(const_cast(event)); - } - } - - return TRUE; -} - -int ttyu_win_which(DWORD code) { - if(code > 0) { - return (int) code; - } - return WHICH_UNKNOWN; -} - -int ttyu_win_ctrl(DWORD state) { - int ctrl = CTRL_NULL; - if(state & RIGHT_ALT_PRESSED || state & LEFT_ALT_PRESSED) { - ctrl |= CTRL_ALT; - } - if(state & RIGHT_CTRL_PRESSED || state & LEFT_CTRL_PRESSED) { - ctrl |= CTRL_CTRL; - } - if(state & SHIFT_PRESSED) { - ctrl |= CTRL_SHIFT; - } - if(state & ENHANCED_KEY) { - ctrl |= CTRL_ENHANCED; - } - if(state & NUMLOCK_ON) { - ctrl |= CTRL_NUMLOCK; - } - if(state & SCROLLLOCK_ON) { - ctrl |= CTRL_SCROLLLOCK; - } - if(state & CAPSLOCK_ON) { - ctrl |= CTRL_CAPSLOCK; - } - return ctrl; -} - -DWORD ttyu_win_state(int ctrl) { - DWORD state = 0; - if(ctrl & CTRL_ALT) { - state |= RIGHT_ALT_PRESSED & LEFT_ALT_PRESSED; - } - if(ctrl & CTRL_CTRL) { - state |= RIGHT_CTRL_PRESSED & LEFT_CTRL_PRESSED; - } - if(ctrl & CTRL_SHIFT) { - state |= SHIFT_PRESSED; - } - if(ctrl & CTRL_ENHANCED) { - state |= ENHANCED_KEY; - } - if(ctrl & CTRL_NUMLOCK) { - state |= NUMLOCK_ON; - } - if(ctrl & CTRL_SCROLLLOCK) { - state |= SCROLLLOCK_ON; - } - if(ctrl & CTRL_CAPSLOCK) { - state |= CAPSLOCK_ON; - } - return state; -} - -bool ttyu_win_scr_update(ttyu_data_t *data, bool initial) { - CONSOLE_SCREEN_BUFFER_INFO con_info; - - if(!GetConsoleScreenBufferInfo(data->hout, &con_info)) { - data->err->msg = ERROR(ERROR_WIN_GET, GetLastError()); - return !(data->err->kill = TRUE); - } - - data->top = (int)con_info.srWindow.Top; - data->width = (int)con_info.dwSize.X; - data->height = (int)con_info.dwSize.Y - data->top; - - data->curx = (int)con_info.dwCursorPosition.X; - data->cury = (int)con_info.dwCursorPosition.Y - data->top; - - if(initial) { - data->base_color = (short)con_info.wAttributes; - } - return TRUE; -} - -void ttyu_win_render(char *c, ttyu_data_t *data) { - short fg = -1; - short bg = -1; - int len = (int)strlen(c); // content length - int i; // position - int j; // lookahead position - short color; - - for(i = 0; i < len; ++i) { - if(c[i] == '\x1b' && c[i+1] == '[') { - j = 1; - while(i+j < len && c[i+j] != 'm') ++j; - - if(j == 4) { - // end token - if(c[i+2] == '3') { - fg = -1; - } else { - bg = -1; - } - } else { - // start token - if(c[i+2] == '3') { // foreground - if(j == 9) { - fg = util_parse_dec(c[i+7]) * 10 + util_parse_dec(c[i+8]); - } else { - fg = util_parse_dec(c[i+7]); - } - } else { // background - if(j == 9) { - bg = util_parse_dec(c[i+7]) * 10 + util_parse_dec(c[i+8]); - } else { - bg = util_parse_dec(c[i+7]); - } - } - } - - color = 0; - if(fg != -1) { - color += fg; - } else { - color += (data->base_color << 4) >> 4; - } - if(bg != -1) { - color += bg << 4; - } else { - color += (data->base_color >> 4) << 4; - } - - SetConsoleTextAttribute(data->hout, color); - - i += j; - } else { - std::cout << c[i]; - } - } - - SetConsoleTextAttribute(data->hout, data->base_color); -} - -bool ttyu_win_clrscr(ttyu_data_t *data, int x, int y, int width, int height) { - COORD coordhome = { x, y }; - DWORD written; - CONSOLE_SCREEN_BUFFER_INFO con_info; - DWORD size = width * height; - - // Fill the entire screen with blanks. - if(!FillConsoleOutputCharacter(data->hout, (TCHAR) ' ', size, coordhome, - &written)) { - data->err->msg = ERROR(ERROR_WIN_FILL, GetLastError()); - return (data->err->kill = FALSE); - } - - // Get the current text attribute. - if(!GetConsoleScreenBufferInfo(data->hout, &con_info)) { - data->err->msg = ERROR(ERROR_WIN_GET, GetLastError()); - return (data->err->kill = FALSE); - } - - // Set the buffer's attributes accordingly. - if( !FillConsoleOutputAttribute(data->hout, con_info.wAttributes, size, - coordhome, &written)) { - data->err->msg = ERROR(ERROR_WIN_FILL, GetLastError()); - return (data->err->kill = FALSE); - } - - // Put the cursor at its home coordinates. - SetConsoleCursorPosition(data->hout, coordhome); - return TRUE; -} - -NAN_METHOD(ttyu_js_c::emit) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - if(obj->running) { - int ev = args[0]->Int32Value(); - INPUT_RECORD in[1]; - DWORD w; - - in[0].EventType = 0; - - switch(ev) { - case EVENT_KEY: - KEY_EVENT_RECORD kev; - - kev.bKeyDown = TRUE; - kev.wVirtualKeyCode = (WORD)args[1]->Int32Value(); - kev.dwControlKeyState = ttyu_win_state(args[2]->Int32Value()); - kev.uChar.UnicodeChar = (WCHAR)kev.wVirtualKeyCode; // TODO - kev.uChar.AsciiChar = (CHAR)kev.wVirtualKeyCode; // TODO - kev.wRepeatCount = 1; - kev.wVirtualScanCode = MapVirtualKey(kev.wVirtualKeyCode, - MAPVK_VK_TO_VSC); - - in[0].EventType = KEY_EVENT; - in[0].Event.KeyEvent = kev; - break; - case EVENT_RESIZE: - WINDOW_BUFFER_SIZE_RECORD wev; - COORD size; - - size.X = args[1]->Int32Value(); - size.Y = args[2]->Int32Value(); - - wev.dwSize = size; - in[0].EventType = WINDOW_BUFFER_SIZE_EVENT; - in[0].Event.WindowBufferSizeEvent = wev; - break; - case EVENT_MOUSEDOWN: - case EVENT_MOUSEUP: - case EVENT_MOUSEMOVE: - case EVENT_MOUSEWHEEL: - case EVENT_MOUSEHWHEEL: - MOUSE_EVENT_RECORD mev; - COORD pos; - - in[0].EventType = MOUSE_EVENT; - pos.X = (short)args[2]->Int32Value(); - pos.Y = (short)args[3]->Int32Value() + obj->data->top; - mev.dwControlKeyState = ttyu_win_state(args[4]->Int32Value()); - - if(ev == EVENT_MOUSEUP) { - mev.dwButtonState = args[1]->Int32Value(); - mev.dwEventFlags = 0; - } else if(ev == EVENT_MOUSEDOWN) { - mev.dwButtonState = args[1]->Int32Value(); - mev.dwEventFlags = 2; - } else if(ev == EVENT_MOUSEMOVE) { - mev.dwEventFlags = 1; - } else if(ev == EVENT_MOUSEWHEEL) { - mev.dwEventFlags = 4; - } else if(ev == EVENT_MOUSEHWHEEL) { - mev.dwEventFlags = 8; - } else { - // invalidate event - in[0].EventType = 0; - } - - mev.dwMousePosition = pos; - in[0].Event.MouseEvent = mev; - break; - default: // EVENT_ERROR, EVENT_SIGNAL - // do nothing - break; - } - - if(in[0].EventType != 0) { - WriteConsoleInput(obj->data->hin, in, 1, &w); - } - } - NanReturnUndefined(); -} - -NAN_GETTER(ttyu_js_c::get_width) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - NanReturnValue(NanNew(obj->data->width)); -} - -NAN_GETTER(ttyu_js_c::get_height) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - NanReturnValue(NanNew(obj->data->height)); +ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), mode(MODE_VT100) { + ee_init(&emitter, ttyu_ee_cb_call, ttyu_ee_compare); } -NAN_GETTER(ttyu_js_c::get_mode) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - NanReturnValue(NanNew(MODE_CMD)); -} - -NAN_GETTER(ttyu_js_c::get_colors) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - NanReturnValue(NanNew(WIN_COLORS)); +ttyu_js_c::~ttyu_js_c() { + running = FALSE; + stop = TRUE; + ee_destroy(&emitter); } -NAN_GETTER(ttyu_js_c::getx) { +NAN_METHOD(ttyu_js_c::js_start) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - ttyu_win_scr_update(obj->data); - NanReturnValue(NanNew(obj->data->curx)); -} + obj->running = TRUE; + obj->stop = FALSE; -NAN_SETTER(ttyu_js_c::setx) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING_VOID(obj); - obj->data->curx = args.Data()->Int32Value(); + obj->hin = GetStdHandle(STD_INPUT_HANDLE); + obj->hout = GetStdHandle(STD_OUTPUT_HANDLE); - CONSOLE_SCREEN_BUFFER_INFOEX con_info; - if(GetConsoleScreenBufferInfoEx(obj->data->hout, &con_info)) { - con_info.dwCursorPosition.X = obj->data->curx; - if(!SetConsoleScreenBufferInfoEx(obj->data->hout, &con_info)) { - obj->data->err->msg = ERROR(ERROR_WIN_SET, GetLastError()); - } - } else { - obj->data->err->msg = ERROR(ERROR_WIN_GET, GetLastError()); + if(INVALID_HANDLE_VALUE == data->hin || INVALID_HANDLE_VALUE == data->hout) { + NanThrowError("invalid std handles"); } -} - -NAN_GETTER(ttyu_js_c::gety) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - ttyu_win_scr_update(obj->data); - NanReturnValue(NanNew(obj->data->cury)); -} -NAN_SETTER(ttyu_js_c::sety) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING_VOID(obj); - obj->data->cury = args.Data()->Int32Value(); + GetConsoleMode(obj->hin, &(obj->old_mode)); + DWORD new_mode = ((obj->old_mode | ENABLE_MOUSE_INPUT | + ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT | ENABLE_WINDOW_INPUT) & + ~(ENABLE_QUICK_EDIT_MODE)); + SetConsoleMode(obj->hin, new_mode); - CONSOLE_SCREEN_BUFFER_INFOEX con_info; - if(GetConsoleScreenBufferInfoEx(obj->data->hout, &con_info)) { - con_info.dwCursorPosition.Y = obj->data->cury; - if(!SetConsoleScreenBufferInfoEx(obj->data->hout, &con_info)) { - obj->data->err->msg = ERROR(ERROR_WIN_SET, GetLastError()); - } - } else { - obj->data->err->msg = ERROR(ERROR_WIN_GET, GetLastError()); - } + NanReturnThis(); } -NAN_METHOD(ttyu_js_c::gotoxy) { +NAN_METHOD(ttyu_js_c::js_stop) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - obj->data->curx = args[0]->Int32Value(); - obj->data->cury = args[1]->Int32Value(); + obj->running = FALSE; + obj->stop = TRUE; - CONSOLE_SCREEN_BUFFER_INFOEX con_info; - if(GetConsoleScreenBufferInfoEx(obj->data->hout, &con_info)) { - con_info.dwCursorPosition.X = obj->data->curx; - con_info.dwCursorPosition.Y = obj->data->cury; - if(!SetConsoleScreenBufferInfoEx(obj->data->hout, &con_info)) { - obj->data->err->msg = ERROR(ERROR_WIN_SET, GetLastError()); - } - } else { - obj->data->err->msg = ERROR(ERROR_WIN_GET, GetLastError()); - } - NanReturnUndefined(); -} + SetConsoleMode(obj->hin, obj->old_mode); -NAN_METHOD(ttyu_js_c::write) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - v8::String::Utf8Value *ch = new v8::String::Utf8Value(args[0]->ToString()); - int fg = args[1]->IsNumber() ? args[1]->Int32Value() : ( - args[1]->IsString() ? util_color( - (new v8::String::Utf8Value(args[1]->ToString()))->operator*()) : - 1); - int bg = args[2]->IsNumber() ? args[2]->Int32Value() : ( - args[2]->IsString() ? util_color( - (new v8::String::Utf8Value(args[2]->ToString()))->operator*()) : - 1); - ttyu_win_render(util_render(ch->operator*(), fg, bg), obj->data); NanReturnThis(); } -NAN_METHOD(ttyu_js_c::beep) { +NAN_METHOD(ttyu_js_c::js_on) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - Beep(750, 300); + uv_mutex_lock(&obj->emitlock); + ee_on(&obj->emitter, args[0]->Int32Value(), + new NanCallback(v8::Local::Cast(args[1]))); + uv_mutex_unlock(&obj->emitlock); NanReturnThis(); } -NAN_METHOD(ttyu_js_c::clear) { +NAN_METHOD(ttyu_js_c::js_off) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - int x = 0; - int y = 0; - int width = obj->data->width; - int height = obj->data->height; - - if(args.Length() == 4 && args[0]->IsNumber() && args[1]->IsNumber() && - args[2]->IsNumber() && args[3]->IsNumber()) { - x = util_max(args[0]->Int32Value(), x); - y = util_max(args[1]->Int32Value(), y); - width = util_min(args[2]->Int32Value(), width); - height = util_min(args[3]->Int32Value(), height); - } - - ttyu_win_clrscr(obj->data, x, y, width, height); + uv_mutex_lock(&obj->emitlock); + ee_off(&obj->emitter, args[0]->Int32Value(), + new NanCallback(v8::Local::Cast(args[1]))); + uv_mutex_unlock(&obj->emitlock); NanReturnThis(); } -NAN_METHOD(ttyu_js_c::prepare) { +NAN_METHOD(ttyu_js_c::js_emit) { NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - v8::String::Utf8Value *ch = new v8::String::Utf8Value(args[0]->ToString()); - int fg = args[1]->IsNumber() ? args[1]->Int32Value() : ( - args[1]->IsString() ? util_color( - (new v8::String::Utf8Value(args[1]->ToString()))->operator*()) : - 1); - int bg = args[2]->IsNumber() ? args[2]->Int32Value() : ( - args[2]->IsString() ? util_color( - (new v8::String::Utf8Value(args[2]->ToString()))->operator*()) : - 1); - NanReturnValue(NanNew(util_render(ch->operator*(), fg, bg))); + NanReturnThis(); } -NAN_METHOD(ttyu_js_c::color) { +NAN_METHOD(ttyu_js_c::js_write) { NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - TTYU_THROW_IF_NOT_RUNNING(obj); - v8::String::Utf8Value *ch = new v8::String::Utf8Value(args[0]->ToString()); - NanReturnValue(NanNew(util_color(ch->operator*()))); + NanReturnThis(); } From 696c616e250bc1b87dfe71499b7beed362d77c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Wed, 22 Apr 2015 10:03:28 +0200 Subject: [PATCH 02/28] fix submodule for travis-ci still refactoring --- .gitmodules | 2 +- include/unix.h | 10 +-- include/win.h | 39 +++++++--- src/unix.cc | 35 +++++---- src/win.cc | 195 ++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 250 insertions(+), 31 deletions(-) diff --git a/.gitmodules b/.gitmodules index ca715d7..66df99d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "deps/ee.c"] path = deps/ee.c - url = https://github.com/bbuecherl/ee.c.git + url = git://github.com/bbuecherl/ee.c.git diff --git a/include/unix.h b/include/unix.h index 0664a46..b52ec12 100644 --- a/include/unix.h +++ b/include/unix.h @@ -100,7 +100,8 @@ TTYU_INLINE int ttyu_unix_which(int c); TTYU_INLINE int ttyu_unix_key(int which); #define PLATFORM_DEPENDENT_FIELDS \ - static void handle(uv_work_t *req); \ + void check_queue(); \ + static void wait(uv_work_t *req); \ static void complete(uv_work_t *req); \ static void curses_thread_func(void *that); \ static int curses_threaded_func(WINDOW *win, void *that); \ @@ -109,14 +110,11 @@ TTYU_INLINE int ttyu_unix_key(int which); WINDOW *win; \ uv_barrier_t barrier; \ uv_mutex_t emitlock; \ + uv_mutex_t emitstacklock; \ uv_mutex_t ungetlock; \ + uv_cond_t condition; \ int mode; \ std::vector unget_stack; \ std::vector emit_stack -typedef struct ttyu_work_s { - ttyu_event_t *event; - ttyu_js_c *data; -} ttyu_work_t; - #endif // INCLUDE_UNIX_H_ diff --git a/include/win.h b/include/win.h index c39a179..65f8695 100644 --- a/include/win.h +++ b/include/win.h @@ -27,6 +27,8 @@ #include +#define WIN_BUFFER_SIZE 128 + #define PLATFORM_DEPENDENT_FIELDS \ HANDLE hin; \ HANDLE hout; \ @@ -36,26 +38,26 @@ ttyu_worker_c worker class ttyu_worker_c : public NanAsyncWorker { -public: + public: class ttyu_progress_c { friend class ttyu_worker_c; - public: + public: void send(const ttyu_event_t *event) const { that_->send_(event); } - private: + private: explicit ttyu_progress_c(ttyu_worker_c *that) : that_(that) {} // prevent movement ttyu_progress_c(const ttyu_progress_c&); void operator=(const ttyu_progress_c&); #if __cplusplus >= 201103L - ttyu_progress_c(const ttyu_progress_c&&) V8_DELETE; - void operator=(const ttyu_progress_c&&) V8_DELETE; + ttyu_progress_c(const ttyu_progress_c&&) V8_DELETE; // NOLINT(build/c++11) + void operator=(const ttyu_progress_c&&) V8_DELETE; // NOLINT(build/c++11) #endif ttyu_worker_c *const that_; }; - ttyu_worker_c(ttyu_js_c *obj) : NanAsyncWorker(NULL), + explicit ttyu_worker_c(ttyu_js_c *obj) : NanAsyncWorker(NULL), asyncdata_(NULL), obj_(obj) { async = new uv_async_t; async_lock = new uv_mutex_t; @@ -69,7 +71,18 @@ class ttyu_worker_c : public NanAsyncWorker { free(asyncdata_); } - void progress(); + void progress() { + uv_mutex_lock(async_lock); + ttyu_event_t *event = asyncdata_; + asyncdata_ = NULL; + uv_mutex_unlock(async_lock); + + if (event) { + handle(event); + } + ttyu_event_destroy(event); + free(event); + } bool execute(const ttyu_progress_c& progress, ttyu_js_c *obj); void handle(ttyu_event_t *event); @@ -82,15 +95,17 @@ class ttyu_worker_c : public NanAsyncWorker { ttyu_progress_c progress(this); uv_barrier_wait(&obj_->barrier); // loop execute until it returns false (error) - while(execute(progress, obj_)); + while (execute(progress, obj_)) continue; } void WorkComplete() { // do nothing } -private: + + private: void send_(const ttyu_event_t *event) { - ttyu_event_t *new_event = (ttyu_event_t *)malloc(sizeof(event)); + ttyu_event_t *new_event = + reinterpret_cast(malloc(sizeof(event))); memcpy(&new_event, &event, sizeof(event)); uv_mutex_lock(async_lock); ttyu_event_t *old_event = asyncdata_; @@ -119,4 +134,8 @@ class ttyu_worker_c : public NanAsyncWorker { ttyu_js_c *obj_; } +int ttyu_win_which(DWORD code); +int ttyu_win_ctrl(DWORD state); +DWORD ttyu_win_state(int ctrl); + #endif // INCLUDE_WIN_H_ diff --git a/src/unix.cc b/src/unix.cc index c8a70ab..4c92478 100644 --- a/src/unix.cc +++ b/src/unix.cc @@ -54,6 +54,7 @@ NAN_METHOD(ttyu_js_c::js_start) { uv_thread_create(&obj->curses_thread, ttyu_js_c::curses_thread_func, obj); NAUV_BARRIER_WAIT(&obj->barrier, TRUE); + obj->check_queue(); NanReturnThis(); } @@ -141,14 +142,27 @@ NAN_METHOD(ttyu_js_c::js_write) { NanReturnThis(); } -void ttyu_js_c::handle(uv_work_t *req) { - DBG("handle"); +void ttyu_js_c::check_queue() { + if (running && !stop) { + uv_work_t work; + work.data = this; + uv_queue_work(uv_default_loop(), &work, wait, (uv_after_work_cb)complete); + } +} + +void ttyu_js_c::wait(uv_work_t *req) { + ttyu_js_c *obj = reinterpret_cast(req->data); + uv_mutex_lock(&obj->emitstacklock); + while (obj->emit_stack.size() == 0) { + uv_cond_wait(&obj->condition, &obj->emitstacklock); + } + uv_mutex_unlock(&obj->emitstacklock); } void ttyu_js_c::complete(uv_work_t *req) { NanScope(); DBG("completed"); - ttyu_work_t *work = static_cast(req->data); +/* ttyu_work_t *work = static_cast(req->data); if (ee_count(&work->data->emitter, work->event->type) == 0 || work->event->type == EVENT_NONE) { return; @@ -204,7 +218,7 @@ void ttyu_js_c::complete(uv_work_t *req) { uv_mutex_lock(&work->data->emitlock); ee_emit(&work->data->emitter, work->event->type, obj); - uv_mutex_unlock(&work->data->emitlock); + uv_mutex_unlock(&work->data->emitlock);*/ } int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { @@ -217,7 +231,7 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { if (c == ERR) { uv_mutex_lock(&obj->ungetlock); if (obj->unget_stack.size() > 0) { - // TODO(@bbuecherl) work on the stack + // TODO(@bbuecherl) work on unget stack uv_mutex_unlock(&obj->ungetlock); } else { uv_mutex_unlock(&obj->ungetlock); @@ -318,14 +332,9 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { } if (event.type != EVENT_NONE) { - /* - uv_work_t work; - ttyu_work_t w; - w.event = &event; - w.data = obj; - work.data = &w; - uv_queue_work(uv_default_loop(), &work, handle, (uv_after_work_cb)complete); - */ + uv_mutex_lock(&obj->emitstacklock); + obj->emit_stack.push_back(&event); + uv_mutex_unlock(&obj->emitstacklock); } return 0; } diff --git a/src/win.cc b/src/win.cc index 08c2434..8f69d97 100644 --- a/src/win.cc +++ b/src/win.cc @@ -42,7 +42,7 @@ NAN_METHOD(ttyu_js_c::js_start) { obj->hin = GetStdHandle(STD_INPUT_HANDLE); obj->hout = GetStdHandle(STD_OUTPUT_HANDLE); - if(INVALID_HANDLE_VALUE == data->hin || INVALID_HANDLE_VALUE == data->hout) { + if (INVALID_HANDLE_VALUE == data->hin || INVALID_HANDLE_VALUE == data->hout) { NanThrowError("invalid std handles"); } @@ -95,3 +95,196 @@ NAN_METHOD(ttyu_js_c::js_write) { NanScope(); NanReturnThis(); } + + +bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, + ttyu_data_t *data) { + DWORD readed; + INPUT_RECORD ir[WIN_BUFFER_SIZE]; + DWORD i; + + if (data->err->msg) { + ttyu_event_t *event = + reinterpret_cast(malloc(sizeof(ttyu_event_t))); + ttyu_event_create_error(event, data->err->msg); + progress.send(const_cast(event)); + if (data->err->kill) { + return FALSE; + } + data->err->msg = NULL; + data->err->kill = FALSE; + } + + ReadConsoleInput(data->hin, ir, WIN_BUFFER_SIZE, &readed); + // exit + if (data->closing) { return FALSE; } + + for (i = 0; i < readed; ++i) { + if (MOUSE_EVENT == ir[i].EventType) { + ttyu_event_t *event = + reinterpret_cast(malloc(sizeof(ttyu_event_t))); + ttyu_event_create_mouse(event, EVENT_ERROR, + static_cast(ir[i].Event.MouseEvent.dwButtonState), + static_cast(ir[i].Event.MouseEvent.dwMousePosition.X), + static_cast(ir[i].Event.MouseEvent.dwMousePosition.Y) - + data->top, ttyu_win_ctrl(ir[i].Event.MouseEvent.dwControlKeyState)); + + if (ir[i].Event.MouseEvent.dwButtonState == 0 && + ir[i].Event.MouseEvent.dwEventFlags == 0) { + event->type = EVENT_MOUSEUP; + } else if (ir[i].Event.MouseEvent.dwEventFlags == 0 || + ir[i].Event.MouseEvent.dwEventFlags == 2) { + event->type = EVENT_MOUSEDOWN; + } else if (ir[i].Event.MouseEvent.dwEventFlags == 1) { + event->type = EVENT_MOUSEMOVE; + } else if (ir[i].Event.MouseEvent.dwEventFlags == 4) { + event->type = EVENT_MOUSEWHEEL; + } else if (ir[i].Event.MouseEvent.dwEventFlags == 8) { + event->type = EVENT_MOUSEHWHEEL; + } + + progress.send(const_cast(event)); + } else if (KEY_EVENT == ir[i].EventType && ir[i].Event.KeyEvent.bKeyDown) { + ttyu_event_t *event = + reinterpret_cast(malloc(sizeof(ttyu_event_t))); + char *ch = reinterpret_cast(malloc(sizeof(char) * 3)); + memcpy(ch, &(ir[i].Event.KeyEvent.uChar.UnicodeChar), sizeof(char) * 2); + ch[2] = '\0'; + + ttyu_event_create_key(event, ttyu_win_ctrl( + ir[i].Event.KeyEvent.dwControlKeyState), ch, + static_cast(ir[i].Event.KeyEvent.wVirtualKeyCode), + ttyu_win_which(ir[i].Event.KeyEvent.wVirtualKeyCode)); + + free(ch); + + progress.send(const_cast(event)); + } else if (WINDOW_BUFFER_SIZE_EVENT == ir[i].EventType) { + ttyu_event_t *event = + reinterpret_cast(malloc(sizeof(ttyu_event_t))); + + if (!ttyu_win_scr_update(data)) { + ttyu_event_create_error(event, data->err->msg); + } else { + ttyu_event_create_resize(event); + } + progress.send(const_cast(event)); + } + } + + return TRUE; +} + +void ttyu_worker_c::handle(ttyu_event_t *event) { + if (ee_count(&obj_->emitter, event->type) == 0 || obj_->stop || + !obj_->running) { + return; + } + + v8::Local obj = NanNew(); + switch (event->type) { + case EVENT_RESIZE: + obj->Set(NanNew("type"), EVENTSTRING_RESIZE); + break; + case EVENT_KEY: + obj->Set(NanNew("type"), EVENTSTRING_KEY); + obj->Set(NanNew("ctrl"), + NanNew(event->key->ctrl)); + obj->Set(NanNew("char"), NanNew(event->key->c)); + obj->Set(NanNew("code"), + NanNew(event->key->code)); + obj->Set(NanNew("which"), + NanNew(event->key->which)); + break; + case EVENT_MOUSEDOWN: + case EVENT_MOUSEUP: + case EVENT_MOUSEMOVE: + case EVENT_MOUSEWHEEL: + case EVENT_MOUSEHWHEEL: + if (event->type == EVENT_MOUSEDOWN) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEDOWN); + } else if (event->type == EVENT_MOUSEUP) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEUP); + } else if (event->type == EVENT_MOUSEMOVE) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEMOVE); + } else if (event->type == EVENT_MOUSEWHEEL) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEWHEEL); + } else if (event->type == EVENT_MOUSEHWHEEL) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEHWHEEL); + } + obj->Set(NanNew("button"), + NanNew(event->mouse->button)); + obj->Set(NanNew("x"), NanNew(event->mouse->x)); + obj->Set(NanNew("y"), NanNew(event->mouse->y)); + obj->Set(NanNew("ctrl"), + NanNew(event->mouse->ctrl)); + break; + default: // EVENT_ERROR, EVENT_SIGNAL + obj->Set(NanNew("type"), EVENTSTRING_ERROR); + obj->Set(NanNew("error"), NanError(event->err)); + event->type = EVENT_ERROR; + break; + } + uv_mutex_lock(&obj_->emitlock); + ee_emit(&obj_->emitter, event->type, obj); + uv_mutex_unlock(&obj_->emitlock); +} + +int ttyu_win_ctrl(DWORD state) { + int ctrl = CTRL_NULL; + if (state & RIGHT_ALT_PRESSED || state & LEFT_ALT_PRESSED) { + ctrl |= CTRL_ALT; + } + if (state & RIGHT_CTRL_PRESSED || state & LEFT_CTRL_PRESSED) { + ctrl |= CTRL_CTRL; + } + if (state & SHIFT_PRESSED) { + ctrl |= CTRL_SHIFT; + } + if (state & ENHANCED_KEY) { + ctrl |= CTRL_ENHANCED; + } + if (state & NUMLOCK_ON) { + ctrl |= CTRL_NUMLOCK; + } + if (state & SCROLLLOCK_ON) { + ctrl |= CTRL_SCROLLLOCK; + } + if (state & CAPSLOCK_ON) { + ctrl |= CTRL_CAPSLOCK; + } + return ctrl; +} + +int ttyu_win_which(DWORD code) { + if (code > 0) { + return static_cast(code); + } + return WHICH_UNKNOWN; +} + +DWORD ttyu_win_state(int ctrl) { + DWORD state = 0; + if (ctrl & CTRL_ALT) { + state |= RIGHT_ALT_PRESSED & LEFT_ALT_PRESSED; + } + if (ctrl & CTRL_CTRL) { + state |= RIGHT_CTRL_PRESSED & LEFT_CTRL_PRESSED; + } + if (ctrl & CTRL_SHIFT) { + state |= SHIFT_PRESSED; + } + if (ctrl & CTRL_ENHANCED) { + state |= ENHANCED_KEY; + } + if (ctrl & CTRL_NUMLOCK) { + state |= NUMLOCK_ON; + } + if (ctrl & CTRL_SCROLLLOCK) { + state |= SCROLLLOCK_ON; + } + if (ctrl & CTRL_CAPSLOCK) { + state |= CAPSLOCK_ON; + } + return state; +} From 4e3c8d8a5a63f64239a7674d57bc36f7908b5b1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Tue, 5 May 2015 15:57:12 +0200 Subject: [PATCH 03/28] unix listener working, updated nan to 1.8.4 unix output is broken --- .gitignore | 2 +- .gitmodules | 2 +- .npmignore | 2 +- include/nauv.h | 38 --------- include/ttyu.h | 1 - include/unix.h | 15 +++- include/utils.h | 59 +++++++++++-- include/win.h | 4 +- package.json | 2 +- src/ttyu.cc | 3 + src/unix.cc | 215 ++++++++++++++++++++++++++++++------------------ src/win.cc | 1 + 12 files changed, 211 insertions(+), 133 deletions(-) delete mode 100644 include/nauv.h diff --git a/.gitignore b/.gitignore index b82470b..164a32a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ build/ node_modules/ -npm-debug.log +*.log .DS_Store TODO.md diff --git a/.gitmodules b/.gitmodules index 66df99d..a70d798 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "deps/ee.c"] path = deps/ee.c - url = git://github.com/bbuecherl/ee.c.git + url = git://github.com/clidejs/ee.c.git diff --git a/.npmignore b/.npmignore index f50596f..7d89165 100644 --- a/.npmignore +++ b/.npmignore @@ -1,6 +1,6 @@ build/ node_modules/ -npm-debug.log +*.log .DS_Store TODO.md diff --git a/include/nauv.h b/include/nauv.h deleted file mode 100644 index 5e0b993..0000000 --- a/include/nauv.h +++ /dev/null @@ -1,38 +0,0 @@ -/* ttyutil - nauv.h - native abstractions for libuv extending nan.h - * https://github.com/clidejs/ttyutil - * - * Copyright Bernhard Bücherl - * - * 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. - */ -#ifndef INCLUDE_NAUV_H_ -#define INCLUDE_NAUV_H_ - -#if NAUV_UVVERSION < 0x010000 -#define NAUV_BARRIER_WAIT(barrier, kill) \ - uv_barrier_wait(barrier); \ - if (kill) \ - uv_barrier_destroy(barrier); -#else -#define NAUV_BARRIER_WAIT(barrier, kill) \ - if (uv_barrier_wait(barrier) > 0) \ - uv_barrier_destroy(barrier); -#endif - -#endif // INCLUDE_NAUV_H_ diff --git a/include/ttyu.h b/include/ttyu.h index 1a41d7e..5cdd81f 100644 --- a/include/ttyu.h +++ b/include/ttyu.h @@ -27,7 +27,6 @@ #include #include -#include #include #include diff --git a/include/unix.h b/include/unix.h index b52ec12..277b656 100644 --- a/include/unix.h +++ b/include/unix.h @@ -99,10 +99,21 @@ TTYU_INLINE int ttyu_unix_which(int c); TTYU_INLINE int ttyu_unix_key(int which); +class emit_worker_c : public NanAsyncWorker { + public: + emit_worker_c(ttyu_js_c *obj) : NanAsyncWorker(NULL), obj(obj) { } + ~emit_worker_c() { } + + void Execute(); + void HandleOKCallback(); + + private: + ttyu_js_c *obj; + std::vector emit_stack; +}; + #define PLATFORM_DEPENDENT_FIELDS \ void check_queue(); \ - static void wait(uv_work_t *req); \ - static void complete(uv_work_t *req); \ static void curses_thread_func(void *that); \ static int curses_threaded_func(WINDOW *win, void *that); \ \ diff --git a/include/utils.h b/include/utils.h index 4071a8f..7944116 100644 --- a/include/utils.h +++ b/include/utils.h @@ -84,11 +84,60 @@ TTYU_INLINE int util_max(int a, int b); TTYU_INLINE int util_min(int a, int b); TTYU_INLINE int util_abs(int a); +// DEBUGGING #ifdef DEBUG -# include -# define DBG(msg) std::cout << msg << "\r\n" -#else -# define DBG(msg) // empty -#endif +#include +#include +#include +#define THREAD_NUM 4 +#define COL_SIZE 25 +TTYU_INLINE void _DBG(const std::string &text, int thread) { + std::ofstream log_file; + log_file.open("debug.log", std::ios_base::app); + log_file << "|"; + int x = COL_SIZE * thread; + + while (x-- > 0) { + log_file << " "; + if (x%COL_SIZE == 0) { + log_file << "|"; + } + } + + log_file << text; + + int tlen = text.length(); + x = COL_SIZE * (THREAD_NUM - thread) - tlen; + while (x-- > 0) { + log_file << " "; + if (x%COL_SIZE == 0) { + log_file << "|"; + } + } + log_file << std::endl; + log_file.close(); +} + +TTYU_INLINE void _DBGHEAD() { + std::ofstream log_file; + log_file.open("debug.log", std::ios_base::app); + log_file << "+-------------------------+-------------------------+----------" + << "---------------+-------------------------+" << std::endl; + log_file << "| ttyutil debug.log " + << " |" << std::endl; + log_file << "+-------------------------+-------------------------+----------" + << "---------------+-------------------------+" << std::endl; + log_file << "| main thread | libuv thread | curs" + << "es thread | emit loop |" << std::endl; + log_file << "+-------------------------+-------------------------+----------" + << "---------------+-------------------------+" << std::endl; + log_file.close(); +} +#define DBG(msg, thread) _DBG(msg, thread); +#define DBGHEAD() _DBGHEAD(); +#else // DEBUG +#define DBG(msg, thread) // undef +#define DBGHEAD() // undef +#endif // DEBUG #endif // INCLUDE_UTILS_H_ diff --git a/include/win.h b/include/win.h index 65f8695..bfe90b2 100644 --- a/include/win.h +++ b/include/win.h @@ -93,7 +93,7 @@ class ttyu_worker_c : public NanAsyncWorker { void Execute() { ttyu_progress_c progress(this); - uv_barrier_wait(&obj_->barrier); + nauv_barrier_kill(&obj_->barrier, FALSE); // loop execute until it returns false (error) while (execute(progress, obj_)) continue; } @@ -132,7 +132,7 @@ class ttyu_worker_c : public NanAsyncWorker { uv_mutex_t *async_lock; ttyu_event_t *asyncdata_; ttyu_js_c *obj_; -} +}; int ttyu_win_which(DWORD code); int ttyu_win_ctrl(DWORD state); diff --git a/package.json b/package.json index 23b3fd3..a128fd8 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ }, "homepage": "https://github.com/clidejs/ttyutil", "dependencies": { - "nan": "1.7.0" + "nan": "1.8.4" }, "devDependencies": { "node-gyp": "1.0.2", diff --git a/src/ttyu.cc b/src/ttyu.cc index 4ceac06..d2fd0e2 100644 --- a/src/ttyu.cc +++ b/src/ttyu.cc @@ -51,6 +51,9 @@ NAN_METHOD(ttyu_js_c::js_new) { // initialize node module void ttyu_js_c::init(v8::Handle exports, v8::Handle module) { + // DBG Header + DBGHEAD(); + v8::Local tpl = NanNew(js_new); tpl->SetClassName(NanNew("ttyu_js_c")); diff --git a/src/unix.cc b/src/unix.cc index 4c92478..788a149 100644 --- a/src/unix.cc +++ b/src/unix.cc @@ -24,38 +24,42 @@ #include ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), mode(MODE_VT100) { + DBG("::ttyu_js_c()", 0); ee_init(&emitter, ttyu_ee_cb_call, ttyu_ee_compare); } ttyu_js_c::~ttyu_js_c() { + DBG("::~ttyu_js_c()", 0); running = FALSE; stop = TRUE; ee_destroy(&emitter); } NAN_METHOD(ttyu_js_c::js_start) { + DBG("::~start()", 0); NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); obj->running = TRUE; obj->stop = FALSE; + DBG(" init screen", 0); obj->win = initscr(); - noecho(); - cbreak(); - keypad(obj->win, TRUE); - mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); - nodelay(obj->win, 0); - mouseinterval(0); + DBG(" init threads", 0); uv_barrier_init(&obj->barrier, 2); uv_mutex_init(&obj->emitlock); + uv_mutex_init(&obj->emitstacklock); uv_mutex_init(&obj->ungetlock); + uv_cond_init(&obj->condition); + DBG(" spawn threads", 0); uv_thread_create(&obj->curses_thread, ttyu_js_c::curses_thread_func, obj); - - NAUV_BARRIER_WAIT(&obj->barrier, TRUE); obj->check_queue(); + DBG(" barrier kill 1", 0); + uv_barrier_wait(&obj->barrier); + uv_barrier_destroy(&obj->barrier); + DBG(" barrier killed 1", 0); NanReturnThis(); } @@ -64,18 +68,24 @@ NAN_METHOD(ttyu_js_c::js_stop) { ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); obj->running = FALSE; obj->stop = TRUE; + endwin(); uv_thread_join(&obj->curses_thread); uv_mutex_destroy(&obj->emitlock); + uv_mutex_destroy(&obj->emitstacklock); uv_mutex_destroy(&obj->ungetlock); + uv_cond_destroy(&obj->condition); NanReturnThis(); } NAN_METHOD(ttyu_js_c::js_on) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + DBG("on", 0); uv_mutex_lock(&obj->emitlock); - ee_on(&obj->emitter, args[0]->Int32Value(), - new NanCallback(v8::Local::Cast(args[1]))); + { + ee_on(&obj->emitter, args[0]->Int32Value(), + new NanCallback(v8::Local::Cast(args[1]))); + } uv_mutex_unlock(&obj->emitlock); NanReturnThis(); } @@ -84,8 +94,10 @@ NAN_METHOD(ttyu_js_c::js_off) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); uv_mutex_lock(&obj->emitlock); - ee_off(&obj->emitter, args[0]->Int32Value(), - new NanCallback(v8::Local::Cast(args[1]))); + { + ee_off(&obj->emitter, args[0]->Int32Value(), + new NanCallback(v8::Local::Cast(args[1]))); + } uv_mutex_unlock(&obj->emitlock); NanReturnThis(); } @@ -131,7 +143,9 @@ NAN_METHOD(ttyu_js_c::js_emit) { if (event.type == EVENT_NONE) { uv_mutex_lock(&obj->ungetlock); - obj->unget_stack.push_back(&event); + { + obj->unget_stack.push_back(&event); + } uv_mutex_unlock(&obj->ungetlock); } NanReturnThis(); @@ -143,87 +157,109 @@ NAN_METHOD(ttyu_js_c::js_write) { } void ttyu_js_c::check_queue() { + DBG("::check_queue()", 0); if (running && !stop) { - uv_work_t work; - work.data = this; - uv_queue_work(uv_default_loop(), &work, wait, (uv_after_work_cb)complete); + NanAsyncQueueWorker(new emit_worker_c(this)); } } -void ttyu_js_c::wait(uv_work_t *req) { - ttyu_js_c *obj = reinterpret_cast(req->data); +void emit_worker_c::Execute() { + DBG("::Execute()", 3); uv_mutex_lock(&obj->emitstacklock); - while (obj->emit_stack.size() == 0) { - uv_cond_wait(&obj->condition, &obj->emitstacklock); + { + while (obj->emit_stack.size() == 0) { + uv_cond_wait(&obj->condition, &obj->emitstacklock); + DBG(" signaled condition", 3); + } + + // copy stack into emit_worker and clear stack + std::copy(obj->emit_stack.begin(), obj->emit_stack.end(), + std::back_inserter(emit_stack)); + obj->emit_stack.clear(); } uv_mutex_unlock(&obj->emitstacklock); + DBG(" finished wait", 3); } -void ttyu_js_c::complete(uv_work_t *req) { +void emit_worker_c::HandleOKCallback() { + DBG("::HandleOKCallback()", 3); NanScope(); - DBG("completed"); -/* ttyu_work_t *work = static_cast(req->data); - if (ee_count(&work->data->emitter, work->event->type) == 0 || - work->event->type == EVENT_NONE) { - return; - } + for(std::vector::iterator it = emit_stack.begin(); + it != emit_stack.end(); ++it) { + ttyu_event_t *event = *it; - v8::Local obj = NanNew(); - switch (work->event->type) { - case EVENT_RESIZE: - obj->Set(NanNew("type"), EVENTSTRING_RESIZE); - break; - case EVENT_KEY: - obj->Set(NanNew("type"), EVENTSTRING_KEY); - obj->Set(NanNew("ctrl"), - NanNew(work->event->key->ctrl)); - obj->Set(NanNew("char"), - NanNew(work->event->key->c)); - obj->Set(NanNew("code"), - NanNew(work->event->key->code)); - obj->Set(NanNew("which"), - NanNew(work->event->key->which)); - break; - case EVENT_MOUSEDOWN: - case EVENT_MOUSEUP: - case EVENT_MOUSEMOVE: - case EVENT_MOUSEWHEEL: - case EVENT_MOUSEHWHEEL: - if (work->event->type == EVENT_MOUSEDOWN) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEDOWN); - } else if (work->event->type == EVENT_MOUSEUP) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEUP); - } else if (work->event->type == EVENT_MOUSEMOVE) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEMOVE); - } else if (work->event->type == EVENT_MOUSEWHEEL) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEWHEEL); - } else if (work->event->type == EVENT_MOUSEHWHEEL) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEHWHEEL); +/* uv_mutex_lock(&obj->emitlock); + {*/ + if(ee_count(&obj->emitter, event->type) == 0 || + event->type == EVENT_NONE) { + continue; // fast skip } - obj->Set(NanNew("button"), - NanNew(work->event->mouse->button)); - obj->Set(NanNew("x"), - NanNew(work->event->mouse->x)); - obj->Set(NanNew("y"), - NanNew(work->event->mouse->y)); - obj->Set(NanNew("ctrl"), - NanNew(work->event->mouse->ctrl)); - break; - default: // EVENT_ERROR, EVENT_SIGNAL - obj->Set(NanNew("type"), EVENTSTRING_ERROR); - obj->Set(NanNew("error"), NanError(work->event->err)); - work->event->type = EVENT_ERROR; - break; - } +/* } + uv_mutex_unlock(&obj->emitlock);*/ - uv_mutex_lock(&work->data->emitlock); - ee_emit(&work->data->emitter, work->event->type, obj); - uv_mutex_unlock(&work->data->emitlock);*/ + v8::Local jsobj = NanNew(); + switch (event->type) { + case EVENT_RESIZE: + jsobj->Set(NanNew("type"), EVENTSTRING_RESIZE); + break; + case EVENT_KEY: + jsobj->Set(NanNew("type"), EVENTSTRING_KEY); + jsobj->Set(NanNew("ctrl"), + NanNew(event->key->ctrl)); + jsobj->Set(NanNew("char"), + NanNew(event->key->c)); + jsobj->Set(NanNew("code"), + NanNew(event->key->code)); + jsobj->Set(NanNew("which"), + NanNew(event->key->which)); + break; + case EVENT_MOUSEDOWN: + case EVENT_MOUSEUP: + case EVENT_MOUSEMOVE: + case EVENT_MOUSEWHEEL: + case EVENT_MOUSEHWHEEL: + if (event->type == EVENT_MOUSEDOWN) { + jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEDOWN); + } else if (event->type == EVENT_MOUSEUP) { + jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEUP); + } else if (event->type == EVENT_MOUSEMOVE) { + jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEMOVE); + } else if (event->type == EVENT_MOUSEWHEEL) { + jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEWHEEL); + } else if (event->type == EVENT_MOUSEHWHEEL) { + jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEHWHEEL); + } + jsobj->Set(NanNew("button"), + NanNew(event->mouse->button)); + jsobj->Set(NanNew("x"), + NanNew(event->mouse->x)); + jsobj->Set(NanNew("y"), + NanNew(event->mouse->y)); + jsobj->Set(NanNew("ctrl"), + NanNew(event->mouse->ctrl)); + break; + default: // EVENT_ERROR, EVENT_SIGNAL + jsobj->Set(NanNew("type"), EVENTSTRING_ERROR); + jsobj->Set(NanNew("error"), NanError(event->err)); + event->type = EVENT_ERROR; + break; + } + + /*uv_mutex_lock(&obj->emitlock); + {*/ + ee_emit(&obj->emitter, event->type, jsobj); + /*} + uv_mutex_unlock(&obj->emitlock);*/ + } + obj->check_queue(); } int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { + DBG("::curses_threaded_func()", 2); ttyu_js_c *obj = static_cast(that); + DBG(" wgetch", 2); int c = wgetch(win); + DBG(" wgetch finished", 2); MEVENT mev; ttyu_event_t event; event.type = EVENT_NONE; @@ -324,29 +360,46 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { ctrl |= CTRL_CMD | CTRL_SHIFT; } else { which = ttyu_unix_which(c); - // if (ch[0] == '^') { - // ctrl |= CTRL_CTRL; - // } + if (sizeof(ch) > 4 && ch[0] == '^') { + ctrl |= CTRL_CTRL; + } } ttyu_event_create_key(&event, ctrl, ch, c, which); } if (event.type != EVENT_NONE) { + DBG(" event catch", 2); uv_mutex_lock(&obj->emitstacklock); - obj->emit_stack.push_back(&event); + { + obj->emit_stack.push_back(&event); + DBG(" signaling condition", 2); + uv_cond_signal(&obj->condition); + DBG(" signaled condition", 2); + } uv_mutex_unlock(&obj->emitstacklock); } + DBG(" event caught", 2); return 0; } void ttyu_js_c::curses_thread_func(void *that) { + DBG("::curses_thread_func()", 1); ttyu_js_c *obj = static_cast(that); - NAUV_BARRIER_WAIT(&obj->barrier, FALSE); + uv_barrier_wait(&obj->barrier); + + DBG(" init screen", 1); + noecho(); + cbreak(); + keypad(obj->win, TRUE); + mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); + nodelay(obj->win, 0); + mouseinterval(0); while (obj->running && !obj->stop) { use_window(obj->win, curses_threaded_func, that); usleep(100); } + DBG(" end window", 1); endwin(); } diff --git a/src/win.cc b/src/win.cc index 8f69d97..161e1a6 100644 --- a/src/win.cc +++ b/src/win.cc @@ -24,6 +24,7 @@ #include ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), mode(MODE_VT100) { + worker(this); ee_init(&emitter, ttyu_ee_cb_call, ttyu_ee_compare); } From 2d5f514b672f1025c0234e1ee6d25996fcf013d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Fri, 8 May 2015 17:23:41 +0200 Subject: [PATCH 04/28] working on windows implementation --- include/ttyu.h | 22 ++++++++++++++++++++++ include/unix.h | 6 +++--- include/utils.h | 6 +++--- include/win.h | 30 ++++++++++++++++-------------- src/unix.cc | 10 +++++----- src/win.cc | 40 +++++++++++++++++++++++----------------- 6 files changed, 72 insertions(+), 42 deletions(-) diff --git a/include/ttyu.h b/include/ttyu.h index 5cdd81f..a903d61 100644 --- a/include/ttyu.h +++ b/include/ttyu.h @@ -49,6 +49,28 @@ #define EVENT_NONE -1 #define EMIT_INTERVAL 20 +// error types +#define E_ALL 0 +#define E_WIN 1 +#define E_UNIX 2 + +// error messages +#define __ERRMSG(XX) \ + XX(0x00, "critical unknown error (0x00)", E_ALL); \ + XX(0x01, "invalid console handle value (0x01)", E_WIN); \ + XX(0x02, "could not get console output buffer information (0x02)", E_WIN); \ + XX(0x03, "could not set console output buffer information (0x03)", E_WIN); \ + XX(0x04, "could not fill console output buffer (0x04)", E_WIN) + +template +TTYU_INLINE T _ERRMSG(int id) { + #define XX(i, name, platform) if (i == id) { return name; } + __ERRMSG(XX); + #undef XX + return ""; +} +#define ERRMSG(id) _ERRMSG(id) + // callback call function for the event emitter int ttyu_ee_cb_call(ee__listener_t *l, EE_DATA_ARG(data)); // callback compare function for the event emitter diff --git a/include/unix.h b/include/unix.h index 277b656..623b072 100644 --- a/include/unix.h +++ b/include/unix.h @@ -99,10 +99,10 @@ TTYU_INLINE int ttyu_unix_which(int c); TTYU_INLINE int ttyu_unix_key(int which); -class emit_worker_c : public NanAsyncWorker { +class ttyu_worker_c : public NanAsyncWorker { public: - emit_worker_c(ttyu_js_c *obj) : NanAsyncWorker(NULL), obj(obj) { } - ~emit_worker_c() { } + explicit ttyu_worker_c(ttyu_js_c *obj) : NanAsyncWorker(NULL), obj(obj) { } + ~ttyu_worker_c() { } void Execute(); void HandleOKCallback(); diff --git a/include/utils.h b/include/utils.h index 7944116..273e074 100644 --- a/include/utils.h +++ b/include/utils.h @@ -86,11 +86,11 @@ TTYU_INLINE int util_abs(int a); // DEBUGGING #ifdef DEBUG +#define THREAD_NUM 4 +#define COL_SIZE 25 #include #include #include -#define THREAD_NUM 4 -#define COL_SIZE 25 TTYU_INLINE void _DBG(const std::string &text, int thread) { std::ofstream log_file; log_file.open("debug.log", std::ios_base::app); @@ -136,7 +136,7 @@ TTYU_INLINE void _DBGHEAD() { #define DBG(msg, thread) _DBG(msg, thread); #define DBGHEAD() _DBGHEAD(); #else // DEBUG -#define DBG(msg, thread) // undef +#define DBG(msg, thread) // undef #define DBGHEAD() // undef #endif // DEBUG diff --git a/include/win.h b/include/win.h index bfe90b2..ef28084 100644 --- a/include/win.h +++ b/include/win.h @@ -29,14 +29,12 @@ #define WIN_BUFFER_SIZE 128 -#define PLATFORM_DEPENDENT_FIELDS \ - HANDLE hin; \ - HANDLE hout; \ - DWORD old_mode; \ - uv_mutex_t emitlock; \ - uv_barrier_t barrier; \ - ttyu_worker_c worker +typedef struct ttyu_error_s { + char *msg; + bool kill; +} ttyu_error_t; +// worker class, heavily inspired by nan's NanAsyncProgressWorker class ttyu_worker_c : public NanAsyncWorker { public: class ttyu_progress_c { @@ -91,12 +89,7 @@ class ttyu_worker_c : public NanAsyncWorker { uv_close(reinterpret_cast(async), async_close_); } - void Execute() { - ttyu_progress_c progress(this); - nauv_barrier_kill(&obj_->barrier, FALSE); - // loop execute until it returns false (error) - while (execute(progress, obj_)) continue; - } + void Execute(); void WorkComplete() { // do nothing @@ -127,13 +120,22 @@ class ttyu_worker_c : public NanAsyncWorker { delete worker; } - uv_async_t *async; uv_mutex_t *async_lock; ttyu_event_t *asyncdata_; ttyu_js_c *obj_; }; +#define PLATFORM_DEPENDENT_FIELDS \ + HANDLE hin; \ + HANDLE hout; \ + DWORD old_mode; \ + DWORD top; \ + uv_mutex_t emitlock; \ + uv_barrier_t barrier; \ + ttyu_error_t *err; \ + ttyu_worker_c worker + int ttyu_win_which(DWORD code); int ttyu_win_ctrl(DWORD state); DWORD ttyu_win_state(int ctrl); diff --git a/src/unix.cc b/src/unix.cc index 788a149..4baae65 100644 --- a/src/unix.cc +++ b/src/unix.cc @@ -159,11 +159,11 @@ NAN_METHOD(ttyu_js_c::js_write) { void ttyu_js_c::check_queue() { DBG("::check_queue()", 0); if (running && !stop) { - NanAsyncQueueWorker(new emit_worker_c(this)); + NanAsyncQueueWorker(new ttyu_worker_c(this)); } } -void emit_worker_c::Execute() { +void ttyu_worker_c::Execute() { DBG("::Execute()", 3); uv_mutex_lock(&obj->emitstacklock); { @@ -181,16 +181,16 @@ void emit_worker_c::Execute() { DBG(" finished wait", 3); } -void emit_worker_c::HandleOKCallback() { +void ttyu_worker_c::HandleOKCallback() { DBG("::HandleOKCallback()", 3); NanScope(); - for(std::vector::iterator it = emit_stack.begin(); + for (std::vector::iterator it = emit_stack.begin(); it != emit_stack.end(); ++it) { ttyu_event_t *event = *it; /* uv_mutex_lock(&obj->emitlock); {*/ - if(ee_count(&obj->emitter, event->type) == 0 || + if (ee_count(&obj->emitter, event->type) == 0 || event->type == EVENT_NONE) { continue; // fast skip } diff --git a/src/win.cc b/src/win.cc index 161e1a6..cae9fe2 100644 --- a/src/win.cc +++ b/src/win.cc @@ -23,8 +23,7 @@ */ #include -ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), mode(MODE_VT100) { - worker(this); +ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), worker(this), top(0) { ee_init(&emitter, ttyu_ee_cb_call, ttyu_ee_compare); } @@ -43,7 +42,7 @@ NAN_METHOD(ttyu_js_c::js_start) { obj->hin = GetStdHandle(STD_INPUT_HANDLE); obj->hout = GetStdHandle(STD_OUTPUT_HANDLE); - if (INVALID_HANDLE_VALUE == data->hin || INVALID_HANDLE_VALUE == data->hout) { + if (INVALID_HANDLE_VALUE == obj->hin || INVALID_HANDLE_VALUE == obj->hout) { NanThrowError("invalid std handles"); } @@ -99,26 +98,26 @@ NAN_METHOD(ttyu_js_c::js_write) { bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, - ttyu_data_t *data) { + ttyu_js_c *obj) { DWORD readed; INPUT_RECORD ir[WIN_BUFFER_SIZE]; DWORD i; - if (data->err->msg) { + if (obj->err->msg) { ttyu_event_t *event = reinterpret_cast(malloc(sizeof(ttyu_event_t))); - ttyu_event_create_error(event, data->err->msg); + ttyu_event_create_error(event, obj->err->msg); progress.send(const_cast(event)); - if (data->err->kill) { + if (obj->err->kill) { return FALSE; } - data->err->msg = NULL; - data->err->kill = FALSE; + obj->err->msg = NULL; + obj->err->kill = FALSE; } - ReadConsoleInput(data->hin, ir, WIN_BUFFER_SIZE, &readed); + ReadConsoleInput(obj->hin, ir, WIN_BUFFER_SIZE, &readed); // exit - if (data->closing) { return FALSE; } + if (obj->stop) { return FALSE; } for (i = 0; i < readed; ++i) { if (MOUSE_EVENT == ir[i].EventType) { @@ -127,8 +126,8 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, ttyu_event_create_mouse(event, EVENT_ERROR, static_cast(ir[i].Event.MouseEvent.dwButtonState), static_cast(ir[i].Event.MouseEvent.dwMousePosition.X), - static_cast(ir[i].Event.MouseEvent.dwMousePosition.Y) - - data->top, ttyu_win_ctrl(ir[i].Event.MouseEvent.dwControlKeyState)); + static_cast(ir[i].Event.MouseEvent.dwMousePosition.Y - obj->top), + ttyu_win_ctrl(ir[i].Event.MouseEvent.dwControlKeyState)); if (ir[i].Event.MouseEvent.dwButtonState == 0 && ir[i].Event.MouseEvent.dwEventFlags == 0) { @@ -164,11 +163,11 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, ttyu_event_t *event = reinterpret_cast(malloc(sizeof(ttyu_event_t))); - if (!ttyu_win_scr_update(data)) { - ttyu_event_create_error(event, data->err->msg); - } else { + //if (!ttyu_win_scr_update(obj)) { + // ttyu_event_create_error(event, obj->err->msg); + //} else { ttyu_event_create_resize(event); - } + //} progress.send(const_cast(event)); } } @@ -231,6 +230,13 @@ void ttyu_worker_c::handle(ttyu_event_t *event) { uv_mutex_unlock(&obj_->emitlock); } +void ttyu_worker_c::Execute() { + ttyu_progress_c progress(this); + uv_barrier_wait(&obj_->barrier); + // loop execute until it returns false (error) + while (execute(progress, obj_)) continue; +} + int ttyu_win_ctrl(DWORD state) { int ctrl = CTRL_NULL; if (state & RIGHT_ALT_PRESSED || state & LEFT_ALT_PRESSED) { From 9bfea7095d7e8d3fa4f50605307120129e7812d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Tue, 12 May 2015 14:23:00 +0200 Subject: [PATCH 05/28] working on windows implementation --- .gitignore | 2 + include/utils.h | 6 +-- src/win.cc | 116 ++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 112 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 164a32a..d6cab7e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ node_modules/ .DS_Store TODO.md + +spec.js diff --git a/include/utils.h b/include/utils.h index 273e074..8a49a16 100644 --- a/include/utils.h +++ b/include/utils.h @@ -91,11 +91,11 @@ TTYU_INLINE int util_abs(int a); #include #include #include -TTYU_INLINE void _DBG(const std::string &text, int thread) { +TTYU_INLINE void _DBG(const std::string &text, int thread) { // NOLINT ??? std::ofstream log_file; log_file.open("debug.log", std::ios_base::app); log_file << "|"; - int x = COL_SIZE * thread; + size_t x = COL_SIZE * thread; while (x-- > 0) { log_file << " "; @@ -106,7 +106,7 @@ TTYU_INLINE void _DBG(const std::string &text, int thread) { log_file << text; - int tlen = text.length(); + size_t tlen = text.length(); x = COL_SIZE * (THREAD_NUM - thread) - tlen; while (x-- > 0) { log_file << " "; diff --git a/src/win.cc b/src/win.cc index cae9fe2..86e98a9 100644 --- a/src/win.cc +++ b/src/win.cc @@ -39,6 +39,10 @@ NAN_METHOD(ttyu_js_c::js_start) { obj->running = TRUE; obj->stop = FALSE; + DBG("::js_start()", 0); + uv_mutex_init(&obj->emitlock); + uv_barrier_init(&obj->barrier, 2); + obj->hin = GetStdHandle(STD_INPUT_HANDLE); obj->hout = GetStdHandle(STD_OUTPUT_HANDLE); @@ -52,6 +56,14 @@ NAN_METHOD(ttyu_js_c::js_start) { ~(ENABLE_QUICK_EDIT_MODE)); SetConsoleMode(obj->hin, new_mode); + DBG(" async queue start", 0); + NanAsyncQueueWorker(&obj->worker); + + DBG(" wait barrier", 0); + uv_barrier_wait(&obj->barrier); + DBG(" destroy barrier", 0); + uv_barrier_destroy(&obj->barrier); + DBG(" destroyed barrier", 0); NanReturnThis(); } @@ -88,36 +100,118 @@ NAN_METHOD(ttyu_js_c::js_off) { NAN_METHOD(ttyu_js_c::js_emit) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + if (obj->running) { + int ev = args[0]->Int32Value(); + INPUT_RECORD in[1]; + DWORD w; + + in[0].EventType = 0; + + switch (ev) { + case EVENT_KEY: + KEY_EVENT_RECORD kev; + + kev.bKeyDown = TRUE; + kev.wVirtualKeyCode = (WORD)args[1]->Int32Value(); + kev.dwControlKeyState = ttyu_win_state(args[2]->Int32Value()); + kev.uChar.UnicodeChar = static_cast(kev.wVirtualKeyCode); + kev.uChar.AsciiChar = static_cast(kev.wVirtualKeyCode); + kev.wRepeatCount = 1; + kev.wVirtualScanCode = MapVirtualKey(kev.wVirtualKeyCode, + MAPVK_VK_TO_VSC); + + in[0].EventType = KEY_EVENT; + in[0].Event.KeyEvent = kev; + break; + case EVENT_RESIZE: + WINDOW_BUFFER_SIZE_RECORD wev; + COORD size; + + size.X = args[1]->Int32Value(); + size.Y = args[2]->Int32Value(); + + wev.dwSize = size; + in[0].EventType = WINDOW_BUFFER_SIZE_EVENT; + in[0].Event.WindowBufferSizeEvent = wev; + break; + case EVENT_MOUSEDOWN: + case EVENT_MOUSEUP: + case EVENT_MOUSEMOVE: + case EVENT_MOUSEWHEEL: + case EVENT_MOUSEHWHEEL: + MOUSE_EVENT_RECORD mev; + COORD pos; + + in[0].EventType = MOUSE_EVENT; + pos.X = static_cast(args[2]->Int32Value()); + pos.Y = static_cast(args[3]->Int32Value() + obj->top); + mev.dwControlKeyState = ttyu_win_state(args[4]->Int32Value()); + + if (ev == EVENT_MOUSEUP) { + mev.dwButtonState = args[1]->Int32Value(); + mev.dwEventFlags = 0; + } else if (ev == EVENT_MOUSEDOWN) { + mev.dwButtonState = args[1]->Int32Value(); + mev.dwEventFlags = 2; + } else if (ev == EVENT_MOUSEMOVE) { + mev.dwEventFlags = 1; + } else if (ev == EVENT_MOUSEWHEEL) { + mev.dwEventFlags = 4; + } else if (ev == EVENT_MOUSEHWHEEL) { + mev.dwEventFlags = 8; + } else { + // invalidate event + in[0].EventType = 0; + } + + mev.dwMousePosition = pos; + in[0].Event.MouseEvent = mev; + break; + default: // EVENT_ERROR, EVENT_SIGNAL + // do nothing + break; + } + + if (in[0].EventType != 0) { + WriteConsoleInput(obj->hin, in, 1, &w); + } + } NanReturnThis(); } NAN_METHOD(ttyu_js_c::js_write) { NanScope(); + printf("%s\r\n", + (new v8::String::Utf8Value(args[0]->ToString()))->operator*()); NanReturnThis(); } bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, ttyu_js_c *obj) { + DBG("::execute()", 2); DWORD readed; INPUT_RECORD ir[WIN_BUFFER_SIZE]; DWORD i; - - if (obj->err->msg) { + DBG(" start", 2); + if (obj->err) { ttyu_event_t *event = reinterpret_cast(malloc(sizeof(ttyu_event_t))); ttyu_event_create_error(event, obj->err->msg); progress.send(const_cast(event)); if (obj->err->kill) { + DBG(" killed", 2); return FALSE; } obj->err->msg = NULL; obj->err->kill = FALSE; } + DBG(" read input", 2); + ReadConsoleInput(obj->hin, ir, WIN_BUFFER_SIZE, &readed); - // exit - if (obj->stop) { return FALSE; } + if (obj->stop) { DBG(" exited", 2); return FALSE; } // exit for (i = 0; i < readed; ++i) { if (MOUSE_EVENT == ir[i].EventType) { @@ -163,19 +257,20 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, ttyu_event_t *event = reinterpret_cast(malloc(sizeof(ttyu_event_t))); - //if (!ttyu_win_scr_update(obj)) { - // ttyu_event_create_error(event, obj->err->msg); - //} else { + // if (!ttyu_win_scr_update(obj)) { + // ttyu_event_create_error(event, obj->err->msg); + // } else { ttyu_event_create_resize(event); - //} + // } progress.send(const_cast(event)); } } - + DBG(" end", 2); return TRUE; } void ttyu_worker_c::handle(ttyu_event_t *event) { + DBG("::handle()", 1); if (ee_count(&obj_->emitter, event->type) == 0 || obj_->stop || !obj_->running) { return; @@ -231,8 +326,11 @@ void ttyu_worker_c::handle(ttyu_event_t *event) { } void ttyu_worker_c::Execute() { + DBG("::Execute()", 1); ttyu_progress_c progress(this); + DBG(" barrier wait", 1); uv_barrier_wait(&obj_->barrier); + DBG(" start execute loop", 1); // loop execute until it returns false (error) while (execute(progress, obj_)) continue; } From ed796b649d0c964f1e93beced268c6ee3a11741c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Wed, 27 May 2015 22:57:00 +0200 Subject: [PATCH 06/28] working on fixing tests --- export.js | 1 + include/ttyu.h | 43 ++++++++++++++++++++++++------------------- include/utils.h | 12 +++++++----- include/win.h | 10 +++++----- src/ttyu.cc | 2 -- src/ttyu_event.cc | 6 +----- src/unix.cc | 39 +++++---------------------------------- src/win.cc | 33 +++++++++++++++++++++++++++------ tests/key.js | 7 ++----- tests/run.js | 12 ++++++------ 10 files changed, 78 insertions(+), 87 deletions(-) diff --git a/export.js b/export.js index 41cdb45..d4637fb 100644 --- a/export.js +++ b/export.js @@ -23,6 +23,7 @@ module.exports = function(ttyu_js_c) { return ttyutil; }, removeListener: off, + off: off, emit:function(ev) { switch(ev.type) { case ttyutil.EVENT.SIGNAL: diff --git a/include/ttyu.h b/include/ttyu.h index a903d61..1b41368 100644 --- a/include/ttyu.h +++ b/include/ttyu.h @@ -29,13 +29,14 @@ #include #include #include +#include // predefine event data and callbacks for ee.c #define EE_DATA_TYPE v8::Local #define EE_DATA_ARG(name) v8::Local name #define EE_CB_TYPE NanCallback * #define EE_CB_ARG(name) NanCallback *name -#include +#include // NOLINT // define TRUE & FALSE #ifndef TRUE @@ -49,27 +50,31 @@ #define EVENT_NONE -1 #define EMIT_INTERVAL 20 -// error types -#define E_ALL 0 -#define E_WIN 1 -#define E_UNIX 2 - // error messages +typedef struct ttyu_error_s { + int id; + const char *msg; +} ttyu_error_t; + #define __ERRMSG(XX) \ - XX(0x00, "critical unknown error (0x00)", E_ALL); \ - XX(0x01, "invalid console handle value (0x01)", E_WIN); \ - XX(0x02, "could not get console output buffer information (0x02)", E_WIN); \ - XX(0x03, "could not set console output buffer information (0x03)", E_WIN); \ - XX(0x04, "could not fill console output buffer (0x04)", E_WIN) - -template -TTYU_INLINE T _ERRMSG(int id) { - #define XX(i, name, platform) if (i == id) { return name; } + XX(0x00, "critical unknown error"); \ + XX(0x01, "invalid console handle value"); \ + XX(0x02, "could not get console output buffer information"); \ + XX(0x03, "could not set console output buffer information"); \ + XX(0x04, "could not fill console output buffer") + +TTYU_INLINE ttyu_error_t _ERRMSG(int id) { + ttyu_error_t err; + err.id = id; + #define XX(i, name) if (i == id) { \ + err.msg = name; \ + return err; \ + } __ERRMSG(XX); #undef XX - return ""; + return _ERRMSG(0); } -#define ERRMSG(id) _ERRMSG(id) +#define ERRMSG(id) &_ERRMSG(id) // callback call function for the event emitter int ttyu_ee_cb_call(ee__listener_t *l, EE_DATA_ARG(data)); @@ -93,11 +98,10 @@ typedef struct ttyu_mouse_s { // event data structure typedef struct ttyu_event_s { int type; - const char *err; ttyu_key_t *key; ttyu_mouse_t *mouse; } ttyu_event_t; -void ttyu_event_create_error(ttyu_event_t *event, const char *err); +void ttyu_event_create_error(ttyu_event_t *event); void ttyu_event_create_resize(ttyu_event_t *event); void ttyu_event_create_key(ttyu_event_t *event, int ctrl, char *c, int code, int which); @@ -132,6 +136,7 @@ class ttyu_js_c : public node::ObjectWrap { static NAN_METHOD(js_write); + ttyu_error_t *err; bool running; bool stop; ee_emitter_t emitter; diff --git a/include/utils.h b/include/utils.h index 8a49a16..c3ec598 100644 --- a/include/utils.h +++ b/include/utils.h @@ -42,6 +42,9 @@ #define EXPORT_GETSET(tpl, name, get, set) \ tpl->InstanceTemplate()->SetAccessor(NanNew(name), (get), (set)) +#define TTYU_TOSTRING(handle) \ + (new v8::String::Utf8Value(handle->ToString()))->operator*() + #if defined(__GNUC__) && !(defined(DEBUG) && DEBUG) # define TTYU_INLINE inline __attribute__((always_inline)) #elif defined(_MSC_VER) && !(defined(DEBUG) && DEBUG) @@ -85,12 +88,11 @@ TTYU_INLINE int util_min(int a, int b); TTYU_INLINE int util_abs(int a); // DEBUGGING +#include +#include #ifdef DEBUG #define THREAD_NUM 4 #define COL_SIZE 25 -#include -#include -#include TTYU_INLINE void _DBG(const std::string &text, int thread) { // NOLINT ??? std::ofstream log_file; log_file.open("debug.log", std::ios_base::app); @@ -136,8 +138,8 @@ TTYU_INLINE void _DBGHEAD() { #define DBG(msg, thread) _DBG(msg, thread); #define DBGHEAD() _DBGHEAD(); #else // DEBUG -#define DBG(msg, thread) // undef -#define DBGHEAD() // undef +#define DBG(msg, thread) +#define DBGHEAD() #endif // DEBUG #endif // INCLUDE_UTILS_H_ diff --git a/include/win.h b/include/win.h index ef28084..c5f6c12 100644 --- a/include/win.h +++ b/include/win.h @@ -29,11 +29,6 @@ #define WIN_BUFFER_SIZE 128 -typedef struct ttyu_error_s { - char *msg; - bool kill; -} ttyu_error_t; - // worker class, heavily inspired by nan's NanAsyncProgressWorker class ttyu_worker_c : public NanAsyncWorker { public: @@ -131,11 +126,16 @@ class ttyu_worker_c : public NanAsyncWorker { HANDLE hout; \ DWORD old_mode; \ DWORD top; \ + DWORD width; \ + DWORD height; \ + DWORD curx; \ + DWORD cury; \ uv_mutex_t emitlock; \ uv_barrier_t barrier; \ ttyu_error_t *err; \ ttyu_worker_c worker +bool ttyu_win_scr_update(ttyu_js_c *obj, bool initial); int ttyu_win_which(DWORD code); int ttyu_win_ctrl(DWORD state); DWORD ttyu_win_state(int ctrl); diff --git a/src/ttyu.cc b/src/ttyu.cc index d2fd0e2..33737dc 100644 --- a/src/ttyu.cc +++ b/src/ttyu.cc @@ -51,8 +51,6 @@ NAN_METHOD(ttyu_js_c::js_new) { // initialize node module void ttyu_js_c::init(v8::Handle exports, v8::Handle module) { - // DBG Header - DBGHEAD(); v8::Local tpl = NanNew(js_new); diff --git a/src/ttyu_event.cc b/src/ttyu_event.cc index cb2215b..d8adf31 100644 --- a/src/ttyu_event.cc +++ b/src/ttyu_event.cc @@ -23,16 +23,14 @@ */ #include -void ttyu_event_create_error(ttyu_event_t *event, const char *err) { +void ttyu_event_create_error(ttyu_event_t *event) { event->type = EVENT_ERROR; - event->err = err; event->key = NULL; event->mouse = NULL; } void ttyu_event_create_resize(ttyu_event_t *event) { event->type = EVENT_RESIZE; - event->err = NULL; event->key = NULL; event->mouse = NULL; } @@ -45,7 +43,6 @@ void ttyu_event_create_key(ttyu_event_t *event, int ctrl, char *c, ch[strlen(c)] = '\0'; event->type = EVENT_KEY; - event->err = NULL; event->key = reinterpret_cast(std::malloc(sizeof(ttyu_key_t))); event->mouse = NULL; @@ -58,7 +55,6 @@ void ttyu_event_create_key(ttyu_event_t *event, int ctrl, char *c, void ttyu_event_create_mouse(ttyu_event_t *event, int type, int button, int x, int y, int ctrl) { event->type = type; - event->err = NULL; event->key = NULL; event->mouse = reinterpret_cast(std::malloc(sizeof(ttyu_mouse_t))); diff --git a/src/unix.cc b/src/unix.cc index 4baae65..dbac541 100644 --- a/src/unix.cc +++ b/src/unix.cc @@ -24,42 +24,34 @@ #include ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), mode(MODE_VT100) { - DBG("::ttyu_js_c()", 0); ee_init(&emitter, ttyu_ee_cb_call, ttyu_ee_compare); } ttyu_js_c::~ttyu_js_c() { - DBG("::~ttyu_js_c()", 0); running = FALSE; stop = TRUE; ee_destroy(&emitter); } NAN_METHOD(ttyu_js_c::js_start) { - DBG("::~start()", 0); NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); obj->running = TRUE; obj->stop = FALSE; - DBG(" init screen", 0); obj->win = initscr(); - DBG(" init threads", 0); uv_barrier_init(&obj->barrier, 2); uv_mutex_init(&obj->emitlock); uv_mutex_init(&obj->emitstacklock); uv_mutex_init(&obj->ungetlock); uv_cond_init(&obj->condition); - DBG(" spawn threads", 0); uv_thread_create(&obj->curses_thread, ttyu_js_c::curses_thread_func, obj); obj->check_queue(); - DBG(" barrier kill 1", 0); uv_barrier_wait(&obj->barrier); uv_barrier_destroy(&obj->barrier); - DBG(" barrier killed 1", 0); NanReturnThis(); } @@ -80,7 +72,6 @@ NAN_METHOD(ttyu_js_c::js_stop) { NAN_METHOD(ttyu_js_c::js_on) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - DBG("on", 0); uv_mutex_lock(&obj->emitlock); { ee_on(&obj->emitter, args[0]->Int32Value(), @@ -153,23 +144,22 @@ NAN_METHOD(ttyu_js_c::js_emit) { NAN_METHOD(ttyu_js_c::js_write) { NanScope(); + printf("%s", TTYU_TOSTRING(args[0])); + refresh(); NanReturnThis(); } void ttyu_js_c::check_queue() { - DBG("::check_queue()", 0); if (running && !stop) { NanAsyncQueueWorker(new ttyu_worker_c(this)); } } void ttyu_worker_c::Execute() { - DBG("::Execute()", 3); uv_mutex_lock(&obj->emitstacklock); { while (obj->emit_stack.size() == 0) { uv_cond_wait(&obj->condition, &obj->emitstacklock); - DBG(" signaled condition", 3); } // copy stack into emit_worker and clear stack @@ -178,24 +168,18 @@ void ttyu_worker_c::Execute() { obj->emit_stack.clear(); } uv_mutex_unlock(&obj->emitstacklock); - DBG(" finished wait", 3); } void ttyu_worker_c::HandleOKCallback() { - DBG("::HandleOKCallback()", 3); NanScope(); for (std::vector::iterator it = emit_stack.begin(); it != emit_stack.end(); ++it) { ttyu_event_t *event = *it; -/* uv_mutex_lock(&obj->emitlock); - {*/ if (ee_count(&obj->emitter, event->type) == 0 || event->type == EVENT_NONE) { continue; // fast skip } -/* } - uv_mutex_unlock(&obj->emitlock);*/ v8::Local jsobj = NanNew(); switch (event->type) { @@ -240,26 +224,19 @@ void ttyu_worker_c::HandleOKCallback() { break; default: // EVENT_ERROR, EVENT_SIGNAL jsobj->Set(NanNew("type"), EVENTSTRING_ERROR); - jsobj->Set(NanNew("error"), NanError(event->err)); + jsobj->Set(NanNew("error"), NanError("...")); event->type = EVENT_ERROR; break; } - /*uv_mutex_lock(&obj->emitlock); - {*/ - ee_emit(&obj->emitter, event->type, jsobj); - /*} - uv_mutex_unlock(&obj->emitlock);*/ + ee_emit(&obj->emitter, event->type, jsobj); } obj->check_queue(); } int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { - DBG("::curses_threaded_func()", 2); ttyu_js_c *obj = static_cast(that); - DBG(" wgetch", 2); int c = wgetch(win); - DBG(" wgetch finished", 2); MEVENT mev; ttyu_event_t event; event.type = EVENT_NONE; @@ -368,26 +345,21 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { } if (event.type != EVENT_NONE) { - DBG(" event catch", 2); uv_mutex_lock(&obj->emitstacklock); { obj->emit_stack.push_back(&event); - DBG(" signaling condition", 2); + std::ofstream _; // why is this necessary??? uv_cond_signal(&obj->condition); - DBG(" signaled condition", 2); } uv_mutex_unlock(&obj->emitstacklock); } - DBG(" event caught", 2); return 0; } void ttyu_js_c::curses_thread_func(void *that) { - DBG("::curses_thread_func()", 1); ttyu_js_c *obj = static_cast(that); uv_barrier_wait(&obj->barrier); - DBG(" init screen", 1); noecho(); cbreak(); keypad(obj->win, TRUE); @@ -399,7 +371,6 @@ void ttyu_js_c::curses_thread_func(void *that) { use_window(obj->win, curses_threaded_func, that); usleep(100); } - DBG(" end window", 1); endwin(); } diff --git a/src/win.cc b/src/win.cc index 86e98a9..900157a 100644 --- a/src/win.cc +++ b/src/win.cc @@ -182,8 +182,7 @@ NAN_METHOD(ttyu_js_c::js_emit) { NAN_METHOD(ttyu_js_c::js_write) { NanScope(); - printf("%s\r\n", - (new v8::String::Utf8Value(args[0]->ToString()))->operator*()); + printf("%s", TTYU_TOSTRING(args[0])); NanReturnThis(); } @@ -257,11 +256,11 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, ttyu_event_t *event = reinterpret_cast(malloc(sizeof(ttyu_event_t))); - // if (!ttyu_win_scr_update(obj)) { - // ttyu_event_create_error(event, obj->err->msg); - // } else { + if (!ttyu_win_scr_update(obj, FALSE)) { + ttyu_event_create_error(event, obj->err->msg); + } else { ttyu_event_create_resize(event); - // } + } progress.send(const_cast(event)); } } @@ -335,6 +334,28 @@ void ttyu_worker_c::Execute() { while (execute(progress, obj_)) continue; } +bool ttyu_win_scr_update(ttyu_js_c *obj, bool initial) { + CONSOLE_SCREEN_BUFFER_INFO con_info; + + if (!GetConsoleScreenBufferInfo(obj->hout, &con_info)) { + /*data->err->msg = ERRMSG(0x02); + return !(data->err->kill = TRUE);*/ + return FALSE; + } + + obj->top = con_info.srWindow.Top; + obj->width = con_info.dwSize.X; + obj->height = con_info.dwSize.Y - obj->top; + + obj->curx = con_info.dwCursorPosition.X; + obj->cury = con_info.dwCursorPosition.Y - obj->top; + + /*if(initial) { + data->base_color = (short)con_info.wAttributes; + } */ + return TRUE; +} + int ttyu_win_ctrl(DWORD state) { int ctrl = CTRL_NULL; if (state & RIGHT_ALT_PRESSED || state & LEFT_ALT_PRESSED) { diff --git a/tests/key.js b/tests/key.js index b7ab482..e42537b 100644 --- a/tests/key.js +++ b/tests/key.js @@ -96,13 +96,10 @@ var unix_required = [ var current = []; -module.exports = function(TTYUtil, expect) { +module.exports = function(ttyu, expect) { describe("TTYUtil `key` event handling", function() { describe(".which", function() { - var ttyu; - before(function() { - ttyu = new TTYUtil(); ttyu.start(); }); @@ -126,7 +123,7 @@ module.exports = function(TTYUtil, expect) { ttyu.removeListener(TTYUtil.EVENT.KEY, el); } setTimeout(function() { - ttyu.destroy(); + ttyu.stop(); done(); }, 100); }); diff --git a/tests/run.js b/tests/run.js index 972dfef..8572825 100644 --- a/tests/run.js +++ b/tests/run.js @@ -1,13 +1,13 @@ -var TTYUtil = require("../export")(require("../build/Release/ttyu")); +var ttyu = require("../export")(require("../build/Release/ttyu")); var expect = require("chai").expect; // test specs -require("./spec")(TTYUtil, expect); +// require("./spec")(ttyu, expect); // test input listeners -require("./key")(TTYUtil, expect); -require("./mouse")(TTYUtil, expect); -//require("./signal")(TTYUtil, expect); +require("./key")(ttyu, expect); +//require("./mouse")(ttyu, expect); +//require("./signal")(ttyu, expect); // test output functions -//require("./output")(TTYUtil, expect); +//require("./output")(ttyu, expect); From 7eda1dec9b9470dc52ec581cd4ea8912215542be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Fri, 29 May 2015 01:00:10 +0200 Subject: [PATCH 07/28] added emit function to unix, added tests for emit .stop() does not quit completely --- include/unix.h | 3 +- src/unix.cc | 77 +++++++++++++++++++++++++++++++++++++++++++------- tests/key.js | 15 ++++++---- 3 files changed, 79 insertions(+), 16 deletions(-) diff --git a/include/unix.h b/include/unix.h index 623b072..7c7b617 100644 --- a/include/unix.h +++ b/include/unix.h @@ -28,6 +28,7 @@ #define NCURSES_OPAQUE FALSE #include #include +#include #define TTYU_UNIX_KW(XX) \ XX(WHICH_DOWN, KEY_DOWN, FALSE); \ @@ -125,7 +126,7 @@ class ttyu_worker_c : public NanAsyncWorker { uv_mutex_t ungetlock; \ uv_cond_t condition; \ int mode; \ - std::vector unget_stack; \ + std::queue unget_stack; \ std::vector emit_stack #endif // INCLUDE_UNIX_H_ diff --git a/src/unix.cc b/src/unix.cc index dbac541..24148c6 100644 --- a/src/unix.cc +++ b/src/unix.cc @@ -132,10 +132,10 @@ NAN_METHOD(ttyu_js_c::js_emit) { break; } - if (event.type == EVENT_NONE) { + if (event.type != EVENT_NONE) { uv_mutex_lock(&obj->ungetlock); { - obj->unget_stack.push_back(&event); + obj->unget_stack.push(event); } uv_mutex_unlock(&obj->ungetlock); } @@ -236,6 +236,7 @@ void ttyu_worker_c::HandleOKCallback() { int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { ttyu_js_c *obj = static_cast(that); + int c = wgetch(win); MEVENT mev; ttyu_event_t event; @@ -243,16 +244,72 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { if (c == ERR) { uv_mutex_lock(&obj->ungetlock); - if (obj->unget_stack.size() > 0) { - // TODO(@bbuecherl) work on unget stack + if (!obj->unget_stack.empty()) { + ttyu_event_t ev = obj->unget_stack.front(); + obj->unget_stack.pop(); uv_mutex_unlock(&obj->ungetlock); + switch(ev.type) { + case EVENT_KEY: + ungetch(ev.key->code); + break; + case EVENT_MOUSEUP: + case EVENT_MOUSEDOWN: + case EVENT_MOUSEMOVE: + mev.x = ev.mouse->x; + mev.y = ev.mouse->y; + mev.bstate = 0; + + if (ev.mouse->ctrl & CTRL_ALT) { mev.bstate |= BUTTON_ALT; } + if (ev.mouse->ctrl & CTRL_CTRL) { mev.bstate |= BUTTON_CTRL; } + if (ev.mouse->ctrl & CTRL_SHIFT) { mev.bstate |= BUTTON_SHIFT; } + + if (ev.type == EVENT_MOUSEMOVE) { + mev.bstate |= REPORT_MOUSE_POSITION; + } else if (ev.type == EVENT_MOUSEUP) { + if (ev.mouse->button == MOUSE_LEFT) { + mev.bstate |= BUTTON1_RELEASED; + } else if (ev.mouse->button == MOUSE_LEFT2) { + mev.bstate |= BUTTON2_RELEASED; + } else if (ev.mouse->button == MOUSE_LEFT3) { + mev.bstate |= BUTTON3_RELEASED; + } else if (ev.mouse->button == MOUSE_LEFT4) { + mev.bstate |= BUTTON4_RELEASED; + } else if (ev.mouse->button == MOUSE_RIGHT) { +#if NCURSES_MOUSE_VERSION > 1 + mev.bstate |= BUTTON5_RELEASED; +#else + mev.bstate |= BUTTON4_RELEASED; +#endif + } + } else if (ev.type == EVENT_MOUSEDOWN) { + if (ev.mouse->button == MOUSE_LEFT) { + mev.bstate |= BUTTON1_PRESSED; + } else if (ev.mouse->button == MOUSE_LEFT2) { + mev.bstate |= BUTTON2_PRESSED; + } else if (ev.mouse->button == MOUSE_LEFT3) { + mev.bstate |= BUTTON3_PRESSED; + } else if (ev.mouse->button == MOUSE_LEFT4) { + mev.bstate |= BUTTON4_PRESSED; + } else if (ev.mouse->button == MOUSE_RIGHT) { +#if NCURSES_MOUSE_VERSION > 1 + mev.bstate |= BUTTON5_PRESSED; +#else + mev.bstate |= BUTTON4_PRESSED; +#endif + } + } + ungetmouse(&mev); + break; + default: + // EVENT_NONE, EVENT_ERROR, EVENT_SIGNAL, EVENT_RESIZE, + // EVENT_MOUSEWHEEL, EVENT_MOUSEHWHEEL + break; + } } else { uv_mutex_unlock(&obj->ungetlock); - return 0; // fast exit } - } - - if (c == KEY_RESIZE) { + return 0; + } else if (c == KEY_RESIZE) { ttyu_event_create_resize(&event); } else if (c == KEY_MOUSE) { if (getmouse(&mev) == OK) { @@ -364,8 +421,8 @@ void ttyu_js_c::curses_thread_func(void *that) { cbreak(); keypad(obj->win, TRUE); mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); - nodelay(obj->win, 0); - mouseinterval(0); + nodelay(obj->win, TRUE); + mouseinterval(FALSE); while (obj->running && !obj->stop) { use_window(obj->win, curses_threaded_func, that); diff --git a/tests/key.js b/tests/key.js index e42537b..3224c59 100644 --- a/tests/key.js +++ b/tests/key.js @@ -106,26 +106,31 @@ module.exports = function(ttyu, expect) { it.each(which, "should recognize character #%s", ['element'], function(element, next) { this.timeout(100); - ttyu.on(TTYUtil.EVENT.KEY, createTest(element, next)); - ttyu.emit(TTYUtil.KeyEvent(element, 0)); + if(!(process.platform !== "win32" && + unix_required.indexOf(element) === -1)) { + ttyu.on(ttyu.EVENT.KEY, createTest(element, next)); + ttyu.emit(ttyu.KeyEvent(element, 0)); + } else { + next(); + } }); afterEach(function() { var el; while((el = current.pop())) { - ttyu.removeListener(TTYUtil.EVENT.KEY, el); + ttyu.removeListener(ttyu.EVENT.KEY, el); } }) after(function(done) { var el; while((el = current.pop())) { - ttyu.removeListener(TTYUtil.EVENT.KEY, el); + ttyu.removeListener(ttyu.EVENT.KEY, el); } setTimeout(function() { ttyu.stop(); done(); - }, 100); + }, 1000); }); function createTest(element, callback) { From b2209c5b894cbb7b82f4fd1479cd0ccb4a6cd809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Mon, 1 Jun 2015 23:49:40 +0200 Subject: [PATCH 08/28] added ncurses as direct dependency --- .gitmodules | 3 ++ binding.gyp | 72 ++++++++++++++++++++++++------------------ build.js | 76 ++++++++++++++++++++++++++++++--------------- deps/ncurses | 1 + include/generated.h | 2 +- include/ttyu.h | 2 +- package.json | 1 - src/ttyu.cc | 19 ++++++++---- src/unix.cc | 2 +- tests/key.js | 2 +- 10 files changed, 113 insertions(+), 67 deletions(-) create mode 160000 deps/ncurses diff --git a/.gitmodules b/.gitmodules index a70d798..198dc21 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "deps/ee.c"] path = deps/ee.c url = git://github.com/clidejs/ee.c.git +[submodule "deps/ncurses"] + path = deps/ncurses + url = git://ncurses.scripts.mit.edu/ncurses.git diff --git a/binding.gyp b/binding.gyp index 213ad49..add87e0 100644 --- a/binding.gyp +++ b/binding.gyp @@ -1,35 +1,45 @@ { - "targets": [ + "targets": [ + { + "target_name": "ttyu", + "include_dirs" : [ + "\n" + - " *\n" + - " * do not change, this file is autogenerated by 'node build',\n" + - " * these constants are set in ./const.js\n" + - " * Build: " + pkg.version + "." + Date.now() + "\n" + - " */\n" + - "#ifndef INCLUDE_GENERATED_H_\n" + - "#define INCLUDE_GENERATED_H_\n" + - "\n"; + " * https://github.com/clidejs/ttyutil\n" + + " *\n" + + " * Copyright Bernhard Bücherl \n" + + " *\n" + + " * do not change, this file is autogenerated by 'node build',\n" + + " * these constants are set in ./const.js\n" + + " * Build: " + pkg.version + "." + Date.now() + "\n" + + " */\n" + + "#ifndef INCLUDE_GENERATED_H_\n" + + "#define INCLUDE_GENERATED_H_\n" + + "\n"; +var REBUILD = process.env.REBUILD || false; +var OS = process.env.OS; for(var name in Const) { - for(var sub in Const[name]) { - cont += "#define " + name.toUpperCase() + "_" + sub.toUpperCase() + - " " + toCpp(Const[name][sub]) + "\n"; - } - cont += "\n"; + for(var sub in Const[name]) { + cont += "#define " + name.toUpperCase() + "_" + sub.toUpperCase() + + " " + toCpp(Const[name][sub]) + "\n"; + } + cont += "\n"; } cont += "#endif // INCLUDE_GENERATED_H_\n"; -fs.writeFile(generated, cont, console.log); - function toCpp(v) { - if(is.String(v)) { - return "NanNew(\"" + v + "\")"; - } else { - return v; - } + if(typeof v === "string") { + return "NanNew(\"" + v + "\")"; + } else { + return v; + } } -// TODO node-gyp rebuild +console.log(" [preinstall]", process.env); +console.log(" [preinstall] write constants to 'generated.h'"); +fs.writeFile(generated, cont, function(err) { + if(err) throw err; + if((!fs.existsSync(path.join(__dirname, "deps", "ncurses", "lib", + "libncurses++.a")) || REBUILD) && process.platform !== "win32") { + console.log(" [preinstall] ncurses './configure'"); + var cfg = cp.spawn("./configure", { + cwd: path.join(__dirname, "deps", "ncurses") + }); + cfg.stdout.pipe(process.stdout); + cfg.stderr.pipe(process.stderr); + cfg.on("exit", function(code) { + if(code !== 0) throw "ncurses ./configure exited with code -" + code; + console.log(" [preinstall] ncurses 'make'"); + var make = cp.spawn("make", { + cwd: path.join(__dirname, "deps", "ncurses") + }); + make.stdout.pipe(process.stdout); + make.stderr.pipe(process.stderr); + make.on("exit", function(code ) { + if(code !== 0) throw "ncurses make exited with code -" + code; + console.log(" [preinstall] finished with code -0"); + }); + }); + } +}); diff --git a/deps/ncurses b/deps/ncurses new file mode 160000 index 0000000..fe7c48d --- /dev/null +++ b/deps/ncurses @@ -0,0 +1 @@ +Subproject commit fe7c48d7d5115212f09b4ec0d84b189a76953f0d diff --git a/include/generated.h b/include/generated.h index 358a68d..4e4748a 100644 --- a/include/generated.h +++ b/include/generated.h @@ -5,7 +5,7 @@ * * do not change, this file is autogenerated by 'node build', * these constants are set in ./const.js - * Build: 0.2.0.1429616750432 + * Build: 0.2.0.1433194848042 */ #ifndef INCLUDE_GENERATED_H_ #define INCLUDE_GENERATED_H_ diff --git a/include/ttyu.h b/include/ttyu.h index 1b41368..871fac9 100644 --- a/include/ttyu.h +++ b/include/ttyu.h @@ -132,7 +132,7 @@ class ttyu_js_c : public node::ObjectWrap { static NAN_METHOD(js_on); static NAN_METHOD(js_off); static NAN_METHOD(js_emit); - // static NAN_METHOD(js_running); + static NAN_METHOD(js_running); static NAN_METHOD(js_write); diff --git a/package.json b/package.json index a128fd8..8947f89 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,6 @@ "pangyp": "2.1.0", "chai": "2.1.2", "mocha": "2.2.1", - "node-is": "0.5.2", "it-each": "0.3.1" }, "engines": { diff --git a/src/ttyu.cc b/src/ttyu.cc index 33737dc..831edb0 100644 --- a/src/ttyu.cc +++ b/src/ttyu.cc @@ -42,10 +42,16 @@ int ttyu_ee_compare(EE_CB_ARG(cb1), EE_CB_ARG(cb2)) { } NAN_METHOD(ttyu_js_c::js_new) { - NanScope(); - ttyu_js_c *obj = new ttyu_js_c(); - obj->Wrap(args.This()); - NanReturnThis(); + NanScope(); + ttyu_js_c *obj = new ttyu_js_c(); + obj->Wrap(args.This()); + NanReturnThis(); +} + +NAN_METHOD(ttyu_js_c::js_running) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + NanReturnValue(obj->running); } // initialize node module @@ -62,11 +68,10 @@ void ttyu_js_c::init(v8::Handle exports, EXPORT_METHOD(tpl, "on", js_on); EXPORT_METHOD(tpl, "off", js_off); EXPORT_METHOD(tpl, "emit", js_emit); - EXPORT_METHOD(tpl, "write", js_write); - module->Set(NanNew("exports"), tpl->GetFunction()); /* EXPORT_GET(tpl, "running", js_running); + EXPORT_GET(tpl, "width", js_width); EXPORT_GET(tpl, "height", js_height); EXPORT_GET(tpl, "mode", js_mode); @@ -78,5 +83,7 @@ void ttyu_js_c::init(v8::Handle exports, EXPORT_METHOD(tpl, "beep", js_beep); EXPORT_METHOD(tpl, "clear", js_clear); EXPORT_METHOD(tpl, "prepare", js_prepare);*/ + + module->Set(NanNew("exports"), tpl->GetFunction()); } NODE_MODULE(ttyu, ttyu_js_c::init); diff --git a/src/unix.cc b/src/unix.cc index 24148c6..4e58393 100644 --- a/src/unix.cc +++ b/src/unix.cc @@ -60,7 +60,7 @@ NAN_METHOD(ttyu_js_c::js_stop) { ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); obj->running = FALSE; obj->stop = TRUE; - endwin(); + delwin(obj->win); uv_thread_join(&obj->curses_thread); uv_mutex_destroy(&obj->emitlock); uv_mutex_destroy(&obj->emitstacklock); diff --git a/tests/key.js b/tests/key.js index 3224c59..7cd813e 100644 --- a/tests/key.js +++ b/tests/key.js @@ -120,7 +120,7 @@ module.exports = function(ttyu, expect) { while((el = current.pop())) { ttyu.removeListener(ttyu.EVENT.KEY, el); } - }) + }); after(function(done) { var el; From 1984a356bff1e84fb121aacaa37d352e9c153a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Tue, 2 Jun 2015 13:58:06 +0200 Subject: [PATCH 09/28] improved build system --- .gitignore | 5 ++--- .npmignore | 6 +++--- .travis.yml | 1 + appveyor.yml | 4 ++++ binding.gyp | 9 ++++++--- build.js | 43 +++++++++++++++++++++++++++++-------------- include/generated.h | 8 ++++---- package.json | 8 +++++--- src/unix.cc | 2 +- 9 files changed, 55 insertions(+), 31 deletions(-) diff --git a/.gitignore b/.gitignore index d6cab7e..8e2822c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ build/ node_modules/ -*.log .DS_Store +generated.h -TODO.md - +*.log spec.js diff --git a/.npmignore b/.npmignore index 7d89165..a7a73d1 100644 --- a/.npmignore +++ b/.npmignore @@ -1,10 +1,10 @@ build/ node_modules/ -*.log .DS_Store +generated.h -TODO.md - +*.log +spec.js .gitignore .travis.yml appveyor.yml diff --git a/.travis.yml b/.travis.yml index e84f4a5..89e44dc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: node_js os: - linux - osx +env: REBUILD=true BDEBUG=true node_js: - "0.8" - "0.10" diff --git a/appveyor.yml b/appveyor.yml index 8e42596..6ab0fc4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,6 +8,10 @@ environment: - nodejs_version: "0.10" - nodejs_version: "0.12" +environment: + REBUILD: true + BDEBUG: true + platform: - x86 - x64 diff --git a/binding.gyp b/binding.gyp index add87e0..0def47d 100644 --- a/binding.gyp +++ b/binding.gyp @@ -13,14 +13,17 @@ "src/ttyu.cc", "src/utils.cc" ], + + # pre install script "actions": [ { - "action_name": "ncurses_build", + "action_name": "preinstall", "inputs": [ "build.js" ], "outputs": [ "" ], "action": [ "node", "build.js" ] } ], + "conditions": [ ["OS=='win'", { "defines": [ @@ -30,10 +33,10 @@ "src/win.cc" ] }, { # "OS!='win" - "include_dirs": [ "deps/ncurses" ], + "include_dirs": [ "../deps/ncurses" ], "link_settings": { "libraries": [ "-lncurses++", "-lncurses" ], - "library_dirs": [ "deps/ncurses/lib" ] + "library_dirs": [ "../deps/ncurses/lib/" ] }, "sources": [ "src/unix.cc" diff --git a/build.js b/build.js index 6fd8475..4f9ef3a 100644 --- a/build.js +++ b/build.js @@ -6,20 +6,20 @@ var Const = require("./const"); var pkg = require("./package.json"); var generated = path.join(__dirname, "include", "generated.h"); -var cont = "/** ttyutil - generated.h - generated headers\n" + +var cont = "/** ttyutil - generated.h - generated header\n" + " * https://github.com/clidejs/ttyutil\n" + " *\n" + " * Copyright Bernhard Bücherl \n" + " *\n" + - " * do not change, this file is autogenerated by 'node build',\n" + - " * these constants are set in ./const.js\n" + - " * Build: " + pkg.version + "." + Date.now() + "\n" + + " * do not change this file,\n" + + " * it is autogenerated by 'npm install',\n" + + " * these constants are set in /const.js\n" + " */\n" + "#ifndef INCLUDE_GENERATED_H_\n" + "#define INCLUDE_GENERATED_H_\n" + "\n"; var REBUILD = process.env.REBUILD || false; -var OS = process.env.OS; +var BDEBUG = process.env.BDEBUG || false; for(var name in Const) { for(var sub in Const[name]) { @@ -39,7 +39,6 @@ function toCpp(v) { } } -console.log(" [preinstall]", process.env); console.log(" [preinstall] write constants to 'generated.h'"); fs.writeFile(generated, cont, function(err) { if(err) throw err; @@ -49,20 +48,36 @@ fs.writeFile(generated, cont, function(err) { var cfg = cp.spawn("./configure", { cwd: path.join(__dirname, "deps", "ncurses") }); - cfg.stdout.pipe(process.stdout); - cfg.stderr.pipe(process.stderr); + if(BDEBUG) { + cfg.stdout.pipe(process.stdout); + cfg.stderr.pipe(process.stderr); + } cfg.on("exit", function(code) { - if(code !== 0) throw "ncurses ./configure exited with code -" + code; + if(code !== 0) throw "ncurses './configure' exited with code -" + code; console.log(" [preinstall] ncurses 'make'"); var make = cp.spawn("make", { cwd: path.join(__dirname, "deps", "ncurses") }); - make.stdout.pipe(process.stdout); - make.stderr.pipe(process.stderr); - make.on("exit", function(code ) { - if(code !== 0) throw "ncurses make exited with code -" + code; - console.log(" [preinstall] finished with code -0"); + if(BDEBUG) { + make.stdout.pipe(process.stdout); + make.stderr.pipe(process.stderr); + } + make.on("exit", function(code) { + if(code !== 0) throw "ncurses 'make' exited with code -" + code; +/* console.log(" [preinstall] ncurses 'make test'"); // TODO + var test = cp.spawn("make", { + cwd: path.join(__dirname, "deps", "ncurses", "test") + }); + if(BDEBUG) + test.stdout.pipe(process.stdout); + test.stderr.pipe(process.stderr); + test.on("exit", function(code) { + if(code !== 0) throw "ncurses 'make test' exited with code -" + code;*/ + console.log(" [preinstall] finished with code -0"); +/* });*/ }); }); + } else { + console.log(" [preinstall] finished with code -0"); } }); diff --git a/include/generated.h b/include/generated.h index 4e4748a..ce56e7f 100644 --- a/include/generated.h +++ b/include/generated.h @@ -1,11 +1,11 @@ -/** ttyutil - generated.h - generated headers +/** ttyutil - generated.h - generated header * https://github.com/clidejs/ttyutil * * Copyright Bernhard Bücherl * - * do not change, this file is autogenerated by 'node build', - * these constants are set in ./const.js - * Build: 0.2.0.1433194848042 + * do not change this file, + * it is autogenerated by 'npm install', + * these constants are set in /const.js */ #ifndef INCLUDE_GENERATED_H_ #define INCLUDE_GENERATED_H_ diff --git a/package.json b/package.json index 8947f89..bf6a90f 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "cross-platform terminal utilities", "main": "index.js", "scripts": { + "prepublish": "npm run-script lint", "lint": "cpplint.py --extensions=h,cc --filter=-runtime/printf include/* src/*", "test": "./node_modules/.bin/mocha tests/run" }, @@ -29,11 +30,12 @@ "nan": "1.8.4" }, "devDependencies": { - "node-gyp": "1.0.2", - "pangyp": "2.1.0", "chai": "2.1.2", + "it-each": "0.3.1", "mocha": "2.2.1", - "it-each": "0.3.1" + "node-gyp": "1.0.2", + "node-is": "^0.5.2", + "pangyp": "2.1.0" }, "engines": { "node": ">=0.8.0" diff --git a/src/unix.cc b/src/unix.cc index 4e58393..6877fb6 100644 --- a/src/unix.cc +++ b/src/unix.cc @@ -248,7 +248,7 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { ttyu_event_t ev = obj->unget_stack.front(); obj->unget_stack.pop(); uv_mutex_unlock(&obj->ungetlock); - switch(ev.type) { + switch (ev.type) { case EVENT_KEY: ungetch(ev.key->code); break; From 22bb4d9f39303d09ed2d1d2b4598f869af44d6a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Tue, 2 Jun 2015 14:26:55 +0200 Subject: [PATCH 10/28] fix linux build errors added fPIC flag to ncurses make --- build.js | 15 ++++----------- package.json | 2 +- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/build.js b/build.js index 4f9ef3a..fbef997 100644 --- a/build.js +++ b/build.js @@ -54,6 +54,9 @@ fs.writeFile(generated, cont, function(err) { } cfg.on("exit", function(code) { if(code !== 0) throw "ncurses './configure' exited with code -" + code; + console.log(" [preinstall] ncurses modify Makefile"); + fs.appendFileSync(path.join(__dirname, "deps", "ncurses", "Makefile"), + "\n# custom override\noverride CFLAGS+=-fPIC\n"); console.log(" [preinstall] ncurses 'make'"); var make = cp.spawn("make", { cwd: path.join(__dirname, "deps", "ncurses") @@ -64,17 +67,7 @@ fs.writeFile(generated, cont, function(err) { } make.on("exit", function(code) { if(code !== 0) throw "ncurses 'make' exited with code -" + code; -/* console.log(" [preinstall] ncurses 'make test'"); // TODO - var test = cp.spawn("make", { - cwd: path.join(__dirname, "deps", "ncurses", "test") - }); - if(BDEBUG) - test.stdout.pipe(process.stdout); - test.stderr.pipe(process.stderr); - test.on("exit", function(code) { - if(code !== 0) throw "ncurses 'make test' exited with code -" + code;*/ - console.log(" [preinstall] finished with code -0"); -/* });*/ + console.log(" [preinstall] finished with code -0"); }); }); } else { diff --git a/package.json b/package.json index bf6a90f..adf1ae8 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "it-each": "0.3.1", "mocha": "2.2.1", "node-gyp": "1.0.2", - "node-is": "^0.5.2", + "node-is": "0.5.2", "pangyp": "2.1.0" }, "engines": { From cc7f73810c051aefee0512db4f16436d90578e1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20B=C3=BCcherl?= Date: Tue, 2 Jun 2015 15:18:37 +0200 Subject: [PATCH 11/28] Delete generated.h --- include/generated.h | 271 -------------------------------------------- 1 file changed, 271 deletions(-) delete mode 100644 include/generated.h diff --git a/include/generated.h b/include/generated.h deleted file mode 100644 index ce56e7f..0000000 --- a/include/generated.h +++ /dev/null @@ -1,271 +0,0 @@ -/** ttyutil - generated.h - generated header - * https://github.com/clidejs/ttyutil - * - * Copyright Bernhard Bücherl - * - * do not change this file, - * it is autogenerated by 'npm install', - * these constants are set in /const.js - */ -#ifndef INCLUDE_GENERATED_H_ -#define INCLUDE_GENERATED_H_ - -#define EVENT_ERROR 0 -#define EVENT_SIGNAL 1 -#define EVENT_RESIZE 2 -#define EVENT_KEY 3 -#define EVENT_MOUSEUP 4 -#define EVENT_MOUSEDOWN 5 -#define EVENT_MOUSEMOVE 6 -#define EVENT_MOUSEWHEEL 7 -#define EVENT_MOUSEHWHEEL 8 - -#define EVENTSTRING_ERROR NanNew("ERROR") -#define EVENTSTRING_SIGNAL NanNew("SIGNAL") -#define EVENTSTRING_RESIZE NanNew("RESIZE") -#define EVENTSTRING_KEY NanNew("KEY") -#define EVENTSTRING_MOUSEUP NanNew("MOUSEUP") -#define EVENTSTRING_MOUSEDOWN NanNew("MOUSEDOWN") -#define EVENTSTRING_MOUSEMOVE NanNew("MOUSEMOVE") -#define EVENTSTRING_MOUSEWHEEL NanNew("MOUSEWHEEL") -#define EVENTSTRING_MOUSEHWHEEL NanNew("MOUSEHWHEEL") - -#define MOUSE_LEFT 1 -#define MOUSE_LEFT2 4 -#define MOUSE_LEFT3 8 -#define MOUSE_LEFT4 16 -#define MOUSE_RIGHT 2 - -#define WHICH_UNKNOWN -1 -#define WHICH_BACK 8 -#define WHICH_BACKSPACE 8 -#define WHICH_TAB 9 -#define WHICH_CLEAR 12 -#define WHICH_RETURN 13 -#define WHICH_ENTER 13 -#define WHICH_SHIFT 16 -#define WHICH_CONTROL 17 -#define WHICH_CTRL 17 -#define WHICH_MENU 18 -#define WHICH_ALT 18 -#define WHICH_PAUSE 19 -#define WHICH_CAPITAL 20 -#define WHICH_CAPSLOCK 20 -#define WHICH_KANA 21 -#define WHICH_HANGUEL 21 -#define WHICH_HANGUL 21 -#define WHICH_JUNJA 23 -#define WHICH_FINAL 24 -#define WHICH_HANJA 25 -#define WHICH_KANJI 25 -#define WHICH_ESCAPE 27 -#define WHICH_ESC 27 -#define WHICH_CONVERT 28 -#define WHICH_NONCONVERT 29 -#define WHICH_ACCEPT 30 -#define WHICH_MODECHANGE 31 -#define WHICH_SPACE 32 -#define WHICH_SPACEBAR 32 -#define WHICH_PRIOR 33 -#define WHICH_PAGE_UP 33 -#define WHICH_PAGEUP 33 -#define WHICH_NEXT 34 -#define WHICH_PAGE_DOWN 34 -#define WHICH_PAGEDOWN 34 -#define WHICH_END 35 -#define WHICH_HOME 36 -#define WHICH_POS1 36 -#define WHICH_LEFT 37 -#define WHICH_UP 38 -#define WHICH_RIGHT 39 -#define WHICH_DOWN 40 -#define WHICH_SELECT 41 -#define WHICH_PRINT 42 -#define WHICH_EXECUTE 43 -#define WHICH_SNAPSHOT 44 -#define WHICH_PRINT_SCREEN 44 -#define WHICH_PRINTSCREEN 44 -#define WHICH_INSERT 45 -#define WHICH_INS 45 -#define WHICH_DELETE 46 -#define WHICH_DEL 46 -#define WHICH_HELP 47 -#define WHICH_CHAR0 48 -#define WHICH_CHAR1 49 -#define WHICH_CHAR2 50 -#define WHICH_CHAR3 51 -#define WHICH_CHAR4 52 -#define WHICH_CHAR5 53 -#define WHICH_CHAR6 54 -#define WHICH_CHAR7 55 -#define WHICH_CHAR8 56 -#define WHICH_CHAR9 57 -#define WHICH_CHARA 65 -#define WHICH_CHARB 66 -#define WHICH_CHARC 67 -#define WHICH_CHARD 68 -#define WHICH_CHARE 69 -#define WHICH_CHARF 70 -#define WHICH_CHARG 71 -#define WHICH_CHARH 72 -#define WHICH_CHARI 73 -#define WHICH_CHARJ 74 -#define WHICH_CHARK 75 -#define WHICH_CHARL 76 -#define WHICH_CHARM 77 -#define WHICH_CHARN 78 -#define WHICH_CHARO 79 -#define WHICH_CHARP 80 -#define WHICH_CHARQ 81 -#define WHICH_CHARR 82 -#define WHICH_CHARS 83 -#define WHICH_CHART 84 -#define WHICH_CHARU 85 -#define WHICH_CHARV 86 -#define WHICH_CHARW 87 -#define WHICH_CHARX 88 -#define WHICH_CHARY 89 -#define WHICH_CHARZ 90 -#define WHICH_LWIN 91 -#define WHICH_LEFT_WIN 91 -#define WHICH_RWIN 92 -#define WHICH_RIGHT_WIN 92 -#define WHICH_APPS 93 -#define WHICH_SLEEP 95 -#define WHICH_NUMPAD0 96 -#define WHICH_NUM0 96 -#define WHICH_NUMPAD1 97 -#define WHICH_NUM1 97 -#define WHICH_NUMPAD2 98 -#define WHICH_NUM2 98 -#define WHICH_NUMPAD3 99 -#define WHICH_NUM3 99 -#define WHICH_NUMPAD4 100 -#define WHICH_NUM4 100 -#define WHICH_NUMPAD5 101 -#define WHICH_NUM5 101 -#define WHICH_NUMPAD6 102 -#define WHICH_NUM6 102 -#define WHICH_NUMPAD7 103 -#define WHICH_NUM7 103 -#define WHICH_NUMPAD8 104 -#define WHICH_NUM8 104 -#define WHICH_NUMPAD9 105 -#define WHICH_NUM9 105 -#define WHICH_MULTIPLY 106 -#define WHICH_MUL 106 -#define WHICH_ADD 107 -#define WHICH_SEPERATOR 108 -#define WHICH_SEP 108 -#define WHICH_SUBSTRACT 109 -#define WHICH_SUB 109 -#define WHICH_DECIMAL 110 -#define WHICH_DIVIDE 111 -#define WHICH_DIV 111 -#define WHICH_F1 112 -#define WHICH_F2 113 -#define WHICH_F3 114 -#define WHICH_F4 115 -#define WHICH_F5 116 -#define WHICH_F6 117 -#define WHICH_F7 118 -#define WHICH_F8 119 -#define WHICH_F9 120 -#define WHICH_F10 121 -#define WHICH_F11 122 -#define WHICH_F12 123 -#define WHICH_F13 124 -#define WHICH_F14 125 -#define WHICH_F15 126 -#define WHICH_F16 127 -#define WHICH_F17 128 -#define WHICH_F18 129 -#define WHICH_F19 130 -#define WHICH_F20 131 -#define WHICH_F21 132 -#define WHICH_F22 133 -#define WHICH_F23 134 -#define WHICH_F24 135 -#define WHICH_NUMLOCK 144 -#define WHICH_SCROLL 145 -#define WHICH_SCROLL_LOCK 145 -#define WHICH_SCROLLLOCK 145 -#define WHICH_LSHIFT 160 -#define WHICH_LEFT_SHIFT 160 -#define WHICH_RSHIFT 161 -#define WHICH_RIGHT_SHIFT 161 -#define WHICH_LCONTROL 162 -#define WHICH_LCTRL 162 -#define WHICH_LEFT_CONTROL 162 -#define WHICH_LEFT_CTRL 162 -#define WHICH_RCONTROL 163 -#define WHICH_RCTRL 163 -#define WHICH_RIGHT_CONTROL 163 -#define WHICH_RIGHT_CTRL 163 -#define WHICH_LMENU 164 -#define WHICH_LEFT_MENU 164 -#define WHICH_RMENU 165 -#define WHICH_RIGHT_MENU 165 -#define WHICH_BROWSER_BACK 166 -#define WHICH_BROWSER_FORWARD 167 -#define WHICH_BROWSER_REFRESH 168 -#define WHICH_BROWSER_STOP 169 -#define WHICH_BROWSER_SEARCH 170 -#define WHICH_BROWSER_FAVORITES 171 -#define WHICH_BROWSER_HOME 172 -#define WHICH_VOLUME_MUTE 173 -#define WHICH_VOLUME_DOWN 174 -#define WHICH_VOLUME_UP 175 -#define WHICH_MEDIA_NEXT_TRACK 176 -#define WHICH_MEDIA_PREV_TRACK 177 -#define WHICH_MEDIA_STOP 178 -#define WHICH_MEDIA_PLAY_PAUSE 179 -#define WHICH_LAUNCH_MAIL 180 -#define WHICH_LAUNCH_MEDIA_SELECT 181 -#define WHICH_LAUNCH_APP1 182 -#define WHICH_LAUNCH_APP2 183 -#define WHICH_OEM_1 186 -#define WHICH_OEM_PLUS 187 -#define WHICH_PLUS 187 -#define WHICH_OEM_COMMA 188 -#define WHICH_COMMA 188 -#define WHICH_OEM_MINUS 189 -#define WHICH_MINUS 189 -#define WHICH_OEM_PERIOD 190 -#define WHICH_PERIOD 190 -#define WHICH_OEM_2 191 -#define WHICH_OEM_3 192 -#define WHICH_OEM_4 219 -#define WHICH_OEM_5 220 -#define WHICH_OEM_6 221 -#define WHICH_OEM_7 222 -#define WHICH_OEM_8 223 -#define WHICH_OEM_102 226 -#define WHICH_PROCESSKEY 229 -#define WHICH_PROCESS 229 -#define WHICH_PACKET 231 -#define WHICH_ATTN 246 -#define WHICH_CRSEL 247 -#define WHICH_EXSEL 248 -#define WHICH_EREOF 249 -#define WHICH_PLAY 250 -#define WHICH_ZOOM 251 -#define WHICH_NONAME 252 -#define WHICH_PA1 253 -#define WHICH_OEM_CLEAR 254 - -#define CTRL_NULL 0 -#define CTRL_ALT 1 -#define CTRL_CTRL 2 -#define CTRL_SHIFT 4 -#define CTRL_ENHANCED 8 -#define CTRL_CMD 16 -#define CTRL_NUMLOCK 32 -#define CTRL_SCROLLLOCK 64 -#define CTRL_CAPSLOCK 128 - -#define MODE_CMD 0 -#define MODE_VT102 1 -#define MODE_VT100 2 - -#endif // INCLUDE_GENERATED_H_ From 05503d3133d449ec1a048d96a64dd11688b4a812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Thu, 4 Jun 2015 20:42:44 +0200 Subject: [PATCH 12/28] reworked structure added debugging functions --- .travis.yml | 2 +- binding.gyp | 4 +-- include/cdebug.h | 47 +++++++++++++++++++++++++++ include/ttyu.h | 1 + include/unix.h | 4 ++- include/utils.h | 55 ------------------------------- include/win.h | 1 - index.js | 2 +- const.js => lib/const.js | 0 export.js => lib/export.js | 0 signal.js => lib/signal.js | 0 src/ttyu.cc | 2 +- src/unix.cc | 66 ++++++++++++++++++++++---------------- src/win.cc | 9 +++--- tests/key.js | 7 ++-- tests/run.js | 2 +- build.js => tools/build.js | 29 ++++++++++------- 17 files changed, 122 insertions(+), 109 deletions(-) create mode 100644 include/cdebug.h rename const.js => lib/const.js (100%) rename export.js => lib/export.js (100%) rename signal.js => lib/signal.js (100%) rename build.js => tools/build.js (73%) diff --git a/.travis.yml b/.travis.yml index 89e44dc..7299b52 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ node_js: - "0.8" - "0.10" - "0.12" - - "iojs-v1.6.4" + - "iojs-v2.2.0" install: - npm install - curl -G -v http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py -o cpplint.py diff --git a/binding.gyp b/binding.gyp index 0def47d..d9a6745 100644 --- a/binding.gyp +++ b/binding.gyp @@ -18,9 +18,9 @@ "actions": [ { "action_name": "preinstall", - "inputs": [ "build.js" ], + "inputs": [ "tools/build.js" ], "outputs": [ "" ], - "action": [ "node", "build.js" ] + "action": [ "node", "tools/build.js" ] } ], diff --git a/include/cdebug.h b/include/cdebug.h new file mode 100644 index 0000000..bdd5354 --- /dev/null +++ b/include/cdebug.h @@ -0,0 +1,47 @@ +/* ttyutil - cdebug.h - header file defining debugging macros + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#ifndef INCLUDE_CDEBUG_H_ +#define INCLUDE_CDEBUG_H_ +#include +#include + +#ifdef CDEBUG +# ifdef CDEBUG_FILE +// TODO(@bbuecherl) write debugging log +# else // CDEBUG_FILE +#define DBG(msg) printf("%s\r\n", msg) +#define SDBG(f, msg) do { \ + std::string str = f; \ + str.append("\r\n"); \ + printf(str.c_str(), msg); \ +} while (0) + +# endif // CDEBUG_FILE +#else // CDEBUG +#define DBG(msg) +#define SDBG(f, msg) + +#endif // CDEBUG + +#endif // INCLUDE_CDEBUG_H_ diff --git a/include/ttyu.h b/include/ttyu.h index 871fac9..bcf5eb8 100644 --- a/include/ttyu.h +++ b/include/ttyu.h @@ -29,6 +29,7 @@ #include #include #include +#include #include // predefine event data and callbacks for ee.c diff --git a/include/unix.h b/include/unix.h index 7c7b617..368ce9b 100644 --- a/include/unix.h +++ b/include/unix.h @@ -29,6 +29,7 @@ #include #include #include +#include #define TTYU_UNIX_KW(XX) \ XX(WHICH_DOWN, KEY_DOWN, FALSE); \ @@ -110,7 +111,7 @@ class ttyu_worker_c : public NanAsyncWorker { private: ttyu_js_c *obj; - std::vector emit_stack; + std::vector emit_stack; }; #define PLATFORM_DEPENDENT_FIELDS \ @@ -126,6 +127,7 @@ class ttyu_worker_c : public NanAsyncWorker { uv_mutex_t ungetlock; \ uv_cond_t condition; \ int mode; \ + bool worker_run; \ std::queue unget_stack; \ std::vector emit_stack diff --git a/include/utils.h b/include/utils.h index c3ec598..26fe775 100644 --- a/include/utils.h +++ b/include/utils.h @@ -87,59 +87,4 @@ TTYU_INLINE int util_max(int a, int b); TTYU_INLINE int util_min(int a, int b); TTYU_INLINE int util_abs(int a); -// DEBUGGING -#include -#include -#ifdef DEBUG -#define THREAD_NUM 4 -#define COL_SIZE 25 -TTYU_INLINE void _DBG(const std::string &text, int thread) { // NOLINT ??? - std::ofstream log_file; - log_file.open("debug.log", std::ios_base::app); - log_file << "|"; - size_t x = COL_SIZE * thread; - - while (x-- > 0) { - log_file << " "; - if (x%COL_SIZE == 0) { - log_file << "|"; - } - } - - log_file << text; - - size_t tlen = text.length(); - x = COL_SIZE * (THREAD_NUM - thread) - tlen; - while (x-- > 0) { - log_file << " "; - if (x%COL_SIZE == 0) { - log_file << "|"; - } - } - log_file << std::endl; - log_file.close(); -} - -TTYU_INLINE void _DBGHEAD() { - std::ofstream log_file; - log_file.open("debug.log", std::ios_base::app); - log_file << "+-------------------------+-------------------------+----------" - << "---------------+-------------------------+" << std::endl; - log_file << "| ttyutil debug.log " - << " |" << std::endl; - log_file << "+-------------------------+-------------------------+----------" - << "---------------+-------------------------+" << std::endl; - log_file << "| main thread | libuv thread | curs" - << "es thread | emit loop |" << std::endl; - log_file << "+-------------------------+-------------------------+----------" - << "---------------+-------------------------+" << std::endl; - log_file.close(); -} -#define DBG(msg, thread) _DBG(msg, thread); -#define DBGHEAD() _DBGHEAD(); -#else // DEBUG -#define DBG(msg, thread) -#define DBGHEAD() -#endif // DEBUG - #endif // INCLUDE_UTILS_H_ diff --git a/include/win.h b/include/win.h index c5f6c12..04b7db5 100644 --- a/include/win.h +++ b/include/win.h @@ -132,7 +132,6 @@ class ttyu_worker_c : public NanAsyncWorker { DWORD cury; \ uv_mutex_t emitlock; \ uv_barrier_t barrier; \ - ttyu_error_t *err; \ ttyu_worker_c worker bool ttyu_win_scr_update(ttyu_js_c *obj, bool initial); diff --git a/index.js b/index.js index 2d4834f..c47085c 100644 --- a/index.js +++ b/index.js @@ -1 +1 @@ -module.exports = require("./export")(require("./build/Release/ttyu")); +module.exports = require("./lib/export")(require("./build/Release/ttyu")); diff --git a/const.js b/lib/const.js similarity index 100% rename from const.js rename to lib/const.js diff --git a/export.js b/lib/export.js similarity index 100% rename from export.js rename to lib/export.js diff --git a/signal.js b/lib/signal.js similarity index 100% rename from signal.js rename to lib/signal.js diff --git a/src/ttyu.cc b/src/ttyu.cc index 831edb0..bad0598 100644 --- a/src/ttyu.cc +++ b/src/ttyu.cc @@ -1,4 +1,4 @@ -/* ttyutil - ttyu.cc - implements threads and additional functions +/* ttyutil - ttyu.cc - implements additional functions * https://github.com/clidejs/ttyutil * * Copyright Bernhard Bücherl diff --git a/src/unix.cc b/src/unix.cc index 6877fb6..f8f44c6 100644 --- a/src/unix.cc +++ b/src/unix.cc @@ -38,10 +38,10 @@ NAN_METHOD(ttyu_js_c::js_start) { ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); obj->running = TRUE; obj->stop = FALSE; - + obj->worker_run = TRUE; obj->win = initscr(); - uv_barrier_init(&obj->barrier, 2); + uv_barrier_init(&obj->barrier, 3); uv_mutex_init(&obj->emitlock); uv_mutex_init(&obj->emitstacklock); uv_mutex_init(&obj->ungetlock); @@ -51,7 +51,6 @@ NAN_METHOD(ttyu_js_c::js_start) { obj->check_queue(); uv_barrier_wait(&obj->barrier); - uv_barrier_destroy(&obj->barrier); NanReturnThis(); } @@ -66,6 +65,7 @@ NAN_METHOD(ttyu_js_c::js_stop) { uv_mutex_destroy(&obj->emitstacklock); uv_mutex_destroy(&obj->ungetlock); uv_cond_destroy(&obj->condition); + uv_barrier_destroy(&obj->barrier); NanReturnThis(); } @@ -158,10 +158,17 @@ void ttyu_js_c::check_queue() { void ttyu_worker_c::Execute() { uv_mutex_lock(&obj->emitstacklock); { + if (obj->worker_run) { + obj->worker_run = FALSE; + uv_barrier_wait(&obj->barrier); + } + while (obj->emit_stack.size() == 0) { uv_cond_wait(&obj->condition, &obj->emitstacklock); } + SDBG("::Execute %zu", obj->emit_stack.size()); + // copy stack into emit_worker and clear stack std::copy(obj->emit_stack.begin(), obj->emit_stack.end(), std::back_inserter(emit_stack)); @@ -172,65 +179,70 @@ void ttyu_worker_c::Execute() { void ttyu_worker_c::HandleOKCallback() { NanScope(); - for (std::vector::iterator it = emit_stack.begin(); - it != emit_stack.end(); ++it) { - ttyu_event_t *event = *it; - - if (ee_count(&obj->emitter, event->type) == 0 || - event->type == EVENT_NONE) { - continue; // fast skip - } + for (std::vector::size_type i = 0; + i < emit_stack.size(); ++i) { + ttyu_event_t event = emit_stack[i]; + SDBG("::HandleOKCallback %d", i); + SDBG(":: %d", event.type); + SDBG(":: %d", event.key->which); + + /*if (ee_count(&obj->emitter, event->type) == 0 || + event->type == EVENT_NONE) { + SDBG("::HandleOkCallback skip %d", event->type); + continue; // fast skip + }*/ v8::Local jsobj = NanNew(); - switch (event->type) { + switch (event.type) { case EVENT_RESIZE: jsobj->Set(NanNew("type"), EVENTSTRING_RESIZE); break; case EVENT_KEY: jsobj->Set(NanNew("type"), EVENTSTRING_KEY); jsobj->Set(NanNew("ctrl"), - NanNew(event->key->ctrl)); + NanNew(event.key->ctrl)); jsobj->Set(NanNew("char"), - NanNew(event->key->c)); + NanNew(event.key->c)); jsobj->Set(NanNew("code"), - NanNew(event->key->code)); + NanNew(event.key->code)); jsobj->Set(NanNew("which"), - NanNew(event->key->which)); + NanNew(event.key->which)); break; case EVENT_MOUSEDOWN: case EVENT_MOUSEUP: case EVENT_MOUSEMOVE: case EVENT_MOUSEWHEEL: case EVENT_MOUSEHWHEEL: - if (event->type == EVENT_MOUSEDOWN) { + if (event.type == EVENT_MOUSEDOWN) { jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEDOWN); - } else if (event->type == EVENT_MOUSEUP) { + } else if (event.type == EVENT_MOUSEUP) { jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEUP); - } else if (event->type == EVENT_MOUSEMOVE) { + } else if (event.type == EVENT_MOUSEMOVE) { jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEMOVE); - } else if (event->type == EVENT_MOUSEWHEEL) { + } else if (event.type == EVENT_MOUSEWHEEL) { jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEWHEEL); - } else if (event->type == EVENT_MOUSEHWHEEL) { + } else if (event.type == EVENT_MOUSEHWHEEL) { jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEHWHEEL); } jsobj->Set(NanNew("button"), - NanNew(event->mouse->button)); + NanNew(event.mouse->button)); jsobj->Set(NanNew("x"), - NanNew(event->mouse->x)); + NanNew(event.mouse->x)); jsobj->Set(NanNew("y"), - NanNew(event->mouse->y)); + NanNew(event.mouse->y)); jsobj->Set(NanNew("ctrl"), - NanNew(event->mouse->ctrl)); + NanNew(event.mouse->ctrl)); break; default: // EVENT_ERROR, EVENT_SIGNAL jsobj->Set(NanNew("type"), EVENTSTRING_ERROR); jsobj->Set(NanNew("error"), NanError("...")); - event->type = EVENT_ERROR; + event.type = EVENT_ERROR; break; } - ee_emit(&obj->emitter, event->type, jsobj); + ee_emit(&obj->emitter, event.type, jsobj); } + emit_stack.clear(); obj->check_queue(); } diff --git a/src/win.cc b/src/win.cc index 900157a..4fc835d 100644 --- a/src/win.cc +++ b/src/win.cc @@ -197,14 +197,13 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, if (obj->err) { ttyu_event_t *event = reinterpret_cast(malloc(sizeof(ttyu_event_t))); - ttyu_event_create_error(event, obj->err->msg); + ttyu_event_create_error(event); progress.send(const_cast(event)); - if (obj->err->kill) { + if (obj->err) { DBG(" killed", 2); return FALSE; } obj->err->msg = NULL; - obj->err->kill = FALSE; } DBG(" read input", 2); @@ -257,7 +256,7 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, reinterpret_cast(malloc(sizeof(ttyu_event_t))); if (!ttyu_win_scr_update(obj, FALSE)) { - ttyu_event_create_error(event, obj->err->msg); + ttyu_event_create_error(event); } else { ttyu_event_create_resize(event); } @@ -315,7 +314,7 @@ void ttyu_worker_c::handle(ttyu_event_t *event) { break; default: // EVENT_ERROR, EVENT_SIGNAL obj->Set(NanNew("type"), EVENTSTRING_ERROR); - obj->Set(NanNew("error"), NanError(event->err)); + obj->Set(NanNew("error"), NanError("TODO")); event->type = EVENT_ERROR; break; } diff --git a/tests/key.js b/tests/key.js index 7cd813e..abfc44c 100644 --- a/tests/key.js +++ b/tests/key.js @@ -1,6 +1,6 @@ require("it-each")({ testPerIteration: true}); var is = require("node-is"); -var Const = require("../const"); +var Const = require("../lib/const"); var which = []; @@ -105,7 +105,7 @@ module.exports = function(ttyu, expect) { it.each(which, "should recognize character #%s", ['element'], function(element, next) { - this.timeout(100); + this.timeout(500); if(!(process.platform !== "win32" && unix_required.indexOf(element) === -1)) { ttyu.on(ttyu.EVENT.KEY, createTest(element, next)); @@ -123,6 +123,7 @@ module.exports = function(ttyu, expect) { }); after(function(done) { + this.timeout(4000); var el; while((el = current.pop())) { ttyu.removeListener(ttyu.EVENT.KEY, el); @@ -130,7 +131,7 @@ module.exports = function(ttyu, expect) { setTimeout(function() { ttyu.stop(); done(); - }, 1000); + }, 2000); }); function createTest(element, callback) { diff --git a/tests/run.js b/tests/run.js index 8572825..1fc038e 100644 --- a/tests/run.js +++ b/tests/run.js @@ -1,4 +1,4 @@ -var ttyu = require("../export")(require("../build/Release/ttyu")); +var ttyu = require("../lib/export")(require("../build/Release/ttyu")); var expect = require("chai").expect; // test specs diff --git a/build.js b/tools/build.js similarity index 73% rename from build.js rename to tools/build.js index fbef997..7224190 100644 --- a/build.js +++ b/tools/build.js @@ -2,10 +2,10 @@ var fs = require("fs"); var path = require("path"); var cp = require("child_process"); -var Const = require("./const"); -var pkg = require("./package.json"); +var Const = require("../lib/const"); +var pkg = require("../package.json"); -var generated = path.join(__dirname, "include", "generated.h"); +var generated = path.join(__dirname, "..", "include", "generated.h"); var cont = "/** ttyutil - generated.h - generated header\n" + " * https://github.com/clidejs/ttyutil\n" + " *\n" + @@ -20,6 +20,7 @@ var cont = "/** ttyutil - generated.h - generated header\n" + "\n"; var REBUILD = process.env.REBUILD || false; var BDEBUG = process.env.BDEBUG || false; +var CDEBUG = process.env.CDEBUG || false; for(var name in Const) { for(var sub in Const[name]) { @@ -28,7 +29,13 @@ for(var name in Const) { } cont += "\n"; } - +if(CDEBUG) { + cont += "#define CDEBUG\n"; + if(CDEBUG === "file") { + cont += "#define CDEBUG_FILE"; + } + cont += "\n"; +} cont += "#endif // INCLUDE_GENERATED_H_\n"; function toCpp(v) { @@ -39,14 +46,17 @@ function toCpp(v) { } } +console.log(" [preinstall] ENV: [ REBUILD='" + + REBUILD + "', BDEBUG='" + BDEBUG + "', CDEBUG='" + CDEBUG + "' ]"); console.log(" [preinstall] write constants to 'generated.h'"); fs.writeFile(generated, cont, function(err) { if(err) throw err; - if((!fs.existsSync(path.join(__dirname, "deps", "ncurses", "lib", + if((!fs.existsSync(path.join(__dirname, "..", "deps", "ncurses", "lib", "libncurses++.a")) || REBUILD) && process.platform !== "win32") { console.log(" [preinstall] ncurses './configure'"); - var cfg = cp.spawn("./configure", { - cwd: path.join(__dirname, "deps", "ncurses") + var cfg = cp.spawn("./configure", ["--with-shared", "--enable-pc-files", + "--enable-widec", "--without-normal"], { + cwd: path.join(__dirname, "..", "deps", "ncurses") }); if(BDEBUG) { cfg.stdout.pipe(process.stdout); @@ -54,12 +64,9 @@ fs.writeFile(generated, cont, function(err) { } cfg.on("exit", function(code) { if(code !== 0) throw "ncurses './configure' exited with code -" + code; - console.log(" [preinstall] ncurses modify Makefile"); - fs.appendFileSync(path.join(__dirname, "deps", "ncurses", "Makefile"), - "\n# custom override\noverride CFLAGS+=-fPIC\n"); console.log(" [preinstall] ncurses 'make'"); var make = cp.spawn("make", { - cwd: path.join(__dirname, "deps", "ncurses") + cwd: path.join(__dirname, "..", "deps", "ncurses") }); if(BDEBUG) { make.stdout.pipe(process.stdout); From 4803a6506f4aa7342584b69bec645ef3b56c940f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Mon, 8 Jun 2015 16:40:49 +0200 Subject: [PATCH 13/28] more improvements --- .travis.yml | 2 +- include/cdebug.h | 8 ++--- include/ttyu.h | 9 +++++ include/unix.h | 6 ++-- include/utils.h | 9 ----- lib/export.js | 53 +++++++++++++++++++++++------ package.json | 2 +- src/ttyu.cc | 17 +++++++--- src/unix.cc | 87 ++++++++++++++++++++++++++++++++++++++++-------- src/win.cc | 10 +++--- tests/key.js | 12 ++----- tools/build.js | 22 ++++++------ 12 files changed, 166 insertions(+), 71 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7299b52..b2c3e4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: node_js os: - linux - osx -env: REBUILD=true BDEBUG=true +env: TTYU_NCURSES_REBUILD=true TTYU_BUILD_DEBUG=true TTYU_CODE_DEBUG=true node_js: - "0.8" - "0.10" diff --git a/include/cdebug.h b/include/cdebug.h index bdd5354..bda3d3f 100644 --- a/include/cdebug.h +++ b/include/cdebug.h @@ -29,16 +29,16 @@ #ifdef CDEBUG # ifdef CDEBUG_FILE // TODO(@bbuecherl) write debugging log -# else // CDEBUG_FILE +# else // ifndef CDEBUG_FILE #define DBG(msg) printf("%s\r\n", msg) -#define SDBG(f, msg) do { \ +#define SDBG(f, ...) do { \ std::string str = f; \ str.append("\r\n"); \ - printf(str.c_str(), msg); \ + printf(str.c_str(), __VA_ARGS__); \ } while (0) # endif // CDEBUG_FILE -#else // CDEBUG +#else // ifndef CDEBUG #define DBG(msg) #define SDBG(f, msg) diff --git a/include/ttyu.h b/include/ttyu.h index bcf5eb8..1b0da74 100644 --- a/include/ttyu.h +++ b/include/ttyu.h @@ -134,6 +134,15 @@ class ttyu_js_c : public node::ObjectWrap { static NAN_METHOD(js_off); static NAN_METHOD(js_emit); static NAN_METHOD(js_running); + static NAN_METHOD(js_getwidth); + static NAN_METHOD(js_getheight); + static NAN_METHOD(js_setwidth); + static NAN_METHOD(js_setheight); + static NAN_METHOD(js_mode); + static NAN_METHOD(js_setx); + static NAN_METHOD(js_getx); + static NAN_METHOD(js_sety); + static NAN_METHOD(js_gety); static NAN_METHOD(js_write); diff --git a/include/unix.h b/include/unix.h index 368ce9b..262b797 100644 --- a/include/unix.h +++ b/include/unix.h @@ -26,10 +26,10 @@ #define INCLUDE_UNIX_H_ #define NCURSES_OPAQUE FALSE +#include #include #include #include -#include #define TTYU_UNIX_KW(XX) \ XX(WHICH_DOWN, KEY_DOWN, FALSE); \ @@ -129,6 +129,6 @@ class ttyu_worker_c : public NanAsyncWorker { int mode; \ bool worker_run; \ std::queue unget_stack; \ - std::vector emit_stack + std::vector emit_stack -#endif // INCLUDE_UNIX_H_ +#endif // INCLUDE_UNIX_H_# diff --git a/include/utils.h b/include/utils.h index 26fe775..90222a3 100644 --- a/include/utils.h +++ b/include/utils.h @@ -33,15 +33,6 @@ t->GetFunction(), v8::ReadOnly); \ } while (0) -#define EXPORT_GET(tpl, name, fn) do { \ - v8::Local t = NanNew(fn); \ - tpl->InstanceTemplate()->SetAccessor(NanNew(name), \ - t->GetFunction()); \ -} while (0) - -#define EXPORT_GETSET(tpl, name, get, set) \ - tpl->InstanceTemplate()->SetAccessor(NanNew(name), (get), (set)) - #define TTYU_TOSTRING(handle) \ (new v8::String::Utf8Value(handle->ToString()))->operator*() diff --git a/lib/export.js b/lib/export.js index d4637fb..48ba3e9 100644 --- a/lib/export.js +++ b/lib/export.js @@ -1,19 +1,22 @@ var Const = require("./const"); var signal = require("./signal"); +var DIRECT = [ + "write", + "running", + "width", + "height", + "mode", + "x", + "y", + "start", + "stop" +]; +var NOP = function() {}; module.exports = function(ttyu_js_c) { var ttyu = new ttyu_js_c(); var ttyutil = { - start: function() { - ttyu.start(); - }, - stop: function() { - ttyu.stop(); - }, - write: function() { - ttyu.write.apply(ttyu, arguments); - }, on: function(ev, listener) { if(ev === ttyutil.EVENT.SIGNAL) { signal.on(ttyu, ttyu, listener); @@ -44,7 +47,37 @@ module.exports = function(ttyu_js_c) { // ERROR, RESIZE break; } - }, + } + } + + for(var i = 0; i < DIRECT.length; ++i) { + applyDirect(DIRECT[i]); + } + + function applyDirect(d) { + if(d in ttyu) { + ttyutil[d] = function() { + ttyu[d].apply(ttyu, arguments); + } + } else if("set" + d in ttyu) { + Object.defineProperty(ttyutil, d, { + __proto__: null, + get: ttyu["set" + d], + set: ttyu["get" + d], + configurable: false, + enumerable: true, + writeable: false + }); + } else { + Object.defineProperty(ttyutil, d, { + __proto__: null, + get: ttyu["get" + d].bind(ttyu), + set: NOP, + configurable: false, + enumerable: true, + writeable: false + }); + } } function off(ev, listener) { diff --git a/package.json b/package.json index adf1ae8..2c738fb 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "prepublish": "npm run-script lint", "lint": "cpplint.py --extensions=h,cc --filter=-runtime/printf include/* src/*", - "test": "./node_modules/.bin/mocha tests/run" + "test": "./node_modules/.bin/mocha tests/run --reporter min" }, "repository": { "type": "git", diff --git a/src/ttyu.cc b/src/ttyu.cc index bad0598..f8bf683 100644 --- a/src/ttyu.cc +++ b/src/ttyu.cc @@ -51,7 +51,7 @@ NAN_METHOD(ttyu_js_c::js_new) { NAN_METHOD(ttyu_js_c::js_running) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - NanReturnValue(obj->running); + NanReturnValue(obj->running ? NanTrue() : NanFalse()); } // initialize node module @@ -61,7 +61,7 @@ void ttyu_js_c::init(v8::Handle exports, v8::Local tpl = NanNew(js_new); tpl->SetClassName(NanNew("ttyu_js_c")); - tpl->InstanceTemplate()->SetInternalFieldCount(19); + tpl->InstanceTemplate()->SetInternalFieldCount(9); EXPORT_METHOD(tpl, "start", js_start); EXPORT_METHOD(tpl, "stop", js_stop); @@ -69,9 +69,18 @@ void ttyu_js_c::init(v8::Handle exports, EXPORT_METHOD(tpl, "off", js_off); EXPORT_METHOD(tpl, "emit", js_emit); EXPORT_METHOD(tpl, "write", js_write); -/* - EXPORT_GET(tpl, "running", js_running); + EXPORT_METHOD(tpl, "getrunning", js_running); + EXPORT_METHOD(tpl, "getwidth", js_getwidth); + EXPORT_METHOD(tpl, "getheight", js_getheight); + EXPORT_METHOD(tpl, "setwidth", js_setwidth); + EXPORT_METHOD(tpl, "setheight", js_setheight); + EXPORT_METHOD(tpl, "getmode", js_mode); + EXPORT_METHOD(tpl, "setx", js_setx); + EXPORT_METHOD(tpl, "getx", js_getx); + EXPORT_METHOD(tpl, "sety", js_sety); + EXPORT_METHOD(tpl, "gety", js_gety); +/* EXPORT_GET(tpl, "width", js_width); EXPORT_GET(tpl, "height", js_height); EXPORT_GET(tpl, "mode", js_mode); diff --git a/src/unix.cc b/src/unix.cc index f8f44c6..de3258f 100644 --- a/src/unix.cc +++ b/src/unix.cc @@ -59,13 +59,17 @@ NAN_METHOD(ttyu_js_c::js_stop) { ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); obj->running = FALSE; obj->stop = TRUE; - delwin(obj->win); + uv_thread_join(&obj->curses_thread); uv_mutex_destroy(&obj->emitlock); uv_mutex_destroy(&obj->emitstacklock); uv_mutex_destroy(&obj->ungetlock); uv_cond_destroy(&obj->condition); uv_barrier_destroy(&obj->barrier); + endwin(); + delwin(obj->win); + + DBG("window deleted"); NanReturnThis(); } @@ -149,6 +153,62 @@ NAN_METHOD(ttyu_js_c::js_write) { NanReturnThis(); } +NAN_METHOD(ttyu_js_c::js_getwidth) { + NanScope(); + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + NanReturnValue(NanNew(w.ws_col)); +} + +NAN_METHOD(ttyu_js_c::js_getheight) { + NanScope(); + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + NanReturnValue(NanNew(w.ws_row)); +} + +NAN_METHOD(ttyu_js_c::js_setwidth) { + NanScope(); + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + resizeterm(args[0]->Int32Value(), w.ws_row); + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_setheight) { + NanScope(); + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + resizeterm(w.ws_col, args[0]->Int32Value()); + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_setx) { + NanScope(); + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_getx) { + NanScope(); + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_sety) { + NanScope(); + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_gety) { + NanScope(); + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_mode) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(obj->mode)); +} + void ttyu_js_c::check_queue() { if (running && !stop) { NanAsyncQueueWorker(new ttyu_worker_c(this)); @@ -182,15 +242,12 @@ void ttyu_worker_c::HandleOKCallback() { for (std::vector::size_type i = 0; i < emit_stack.size(); ++i) { ttyu_event_t event = emit_stack[i]; - SDBG("::HandleOKCallback %d", i); - SDBG(":: %d", event.type); - SDBG(":: %d", event.key->which); + SDBG("::HandleOKCallback %d %d", i, event.type); - /*if (ee_count(&obj->emitter, event->type) == 0 || - event->type == EVENT_NONE) { - SDBG("::HandleOkCallback skip %d", event->type); + if (ee_count(&obj->emitter, event.type) == 0 || + event.type == EVENT_NONE) { continue; // fast skip - }*/ + } v8::Local jsobj = NanNew(); switch (event.type) { @@ -312,9 +369,12 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { } ungetmouse(&mev); break; + case EVENT_MOUSEWHEEL: + case EVENT_MOUSEHWHEEL: + // TODO(@bbuecherl) + break; default: - // EVENT_NONE, EVENT_ERROR, EVENT_SIGNAL, EVENT_RESIZE, - // EVENT_MOUSEWHEEL, EVENT_MOUSEHWHEEL + // EVENT_NONE, EVENT_ERROR, EVENT_SIGNAL, EVENT_RESIZE break; } } else { @@ -416,8 +476,7 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { if (event.type != EVENT_NONE) { uv_mutex_lock(&obj->emitstacklock); { - obj->emit_stack.push_back(&event); - std::ofstream _; // why is this necessary??? + obj->emit_stack.push_back(event); uv_cond_signal(&obj->condition); } uv_mutex_unlock(&obj->emitstacklock); @@ -427,7 +486,6 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { void ttyu_js_c::curses_thread_func(void *that) { ttyu_js_c *obj = static_cast(that); - uv_barrier_wait(&obj->barrier); noecho(); cbreak(); @@ -436,11 +494,12 @@ void ttyu_js_c::curses_thread_func(void *that) { nodelay(obj->win, TRUE); mouseinterval(FALSE); + uv_barrier_wait(&obj->barrier); + while (obj->running && !obj->stop) { use_window(obj->win, curses_threaded_func, that); usleep(100); } - endwin(); } TTYU_INLINE int ttyu_unix_key(int which) { diff --git a/src/win.cc b/src/win.cc index 4fc835d..2d7760d 100644 --- a/src/win.cc +++ b/src/win.cc @@ -39,7 +39,7 @@ NAN_METHOD(ttyu_js_c::js_start) { obj->running = TRUE; obj->stop = FALSE; - DBG("::js_start()", 0); + DBG("::js_start()"); uv_mutex_init(&obj->emitlock); uv_barrier_init(&obj->barrier, 2); @@ -56,14 +56,14 @@ NAN_METHOD(ttyu_js_c::js_start) { ~(ENABLE_QUICK_EDIT_MODE)); SetConsoleMode(obj->hin, new_mode); - DBG(" async queue start", 0); + DBG(" async queue start"); NanAsyncQueueWorker(&obj->worker); - DBG(" wait barrier", 0); + DBG(" wait barrier"); uv_barrier_wait(&obj->barrier); - DBG(" destroy barrier", 0); + DBG(" destroy barrier"); uv_barrier_destroy(&obj->barrier); - DBG(" destroyed barrier", 0); + DBG(" destroyed barrier"); NanReturnThis(); } diff --git a/tests/key.js b/tests/key.js index abfc44c..6075d3e 100644 --- a/tests/key.js +++ b/tests/key.js @@ -122,16 +122,8 @@ module.exports = function(ttyu, expect) { } }); - after(function(done) { - this.timeout(4000); - var el; - while((el = current.pop())) { - ttyu.removeListener(ttyu.EVENT.KEY, el); - } - setTimeout(function() { - ttyu.stop(); - done(); - }, 2000); + after(function() { + ttyu.stop(); }); function createTest(element, callback) { diff --git a/tools/build.js b/tools/build.js index 7224190..b3f51c5 100644 --- a/tools/build.js +++ b/tools/build.js @@ -18,9 +18,9 @@ var cont = "/** ttyutil - generated.h - generated header\n" + "#ifndef INCLUDE_GENERATED_H_\n" + "#define INCLUDE_GENERATED_H_\n" + "\n"; -var REBUILD = process.env.REBUILD || false; -var BDEBUG = process.env.BDEBUG || false; -var CDEBUG = process.env.CDEBUG || false; +var TTYU_NCURSES_REBUILD = process.env.TTYU_NCURSES_REBUILD || false; +var TTYU_BUILD_DEBUG = process.env.TTYU_BUILD_DEBUG || false; +var TTYU_CODE_DEBUG = process.env.TTYU_CODE_DEBUG || false; for(var name in Const) { for(var sub in Const[name]) { @@ -29,9 +29,9 @@ for(var name in Const) { } cont += "\n"; } -if(CDEBUG) { +if(TTYU_CODE_DEBUG) { cont += "#define CDEBUG\n"; - if(CDEBUG === "file") { + if(TTYU_CODE_DEBUG === "file") { cont += "#define CDEBUG_FILE"; } cont += "\n"; @@ -46,19 +46,21 @@ function toCpp(v) { } } -console.log(" [preinstall] ENV: [ REBUILD='" + - REBUILD + "', BDEBUG='" + BDEBUG + "', CDEBUG='" + CDEBUG + "' ]"); +console.log(" [preinstall] ENV: [ TTYU_NCURSES_REBUILD='" + + TTYU_NCURSES_REBUILD + "', TTYU_BUILD_DEBUG='" + TTYU_BUILD_DEBUG + + "', TTYU_CODE_DEBUG='" + TTYU_CODE_DEBUG + "' ]"); console.log(" [preinstall] write constants to 'generated.h'"); fs.writeFile(generated, cont, function(err) { if(err) throw err; if((!fs.existsSync(path.join(__dirname, "..", "deps", "ncurses", "lib", - "libncurses++.a")) || REBUILD) && process.platform !== "win32") { + "libncurses++.a")) || TTYU_NCURSES_REBUILD) && + process.platform !== "win32") { console.log(" [preinstall] ncurses './configure'"); var cfg = cp.spawn("./configure", ["--with-shared", "--enable-pc-files", "--enable-widec", "--without-normal"], { cwd: path.join(__dirname, "..", "deps", "ncurses") }); - if(BDEBUG) { + if(TTYU_BUILD_DEBUG) { cfg.stdout.pipe(process.stdout); cfg.stderr.pipe(process.stderr); } @@ -68,7 +70,7 @@ fs.writeFile(generated, cont, function(err) { var make = cp.spawn("make", { cwd: path.join(__dirname, "..", "deps", "ncurses") }); - if(BDEBUG) { + if(TTYU_BUILD_DEBUG) { make.stdout.pipe(process.stdout); make.stderr.pipe(process.stderr); } From 06de70fad95a470c102b88e80cbc2e8c5e28a016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Mon, 8 Jun 2015 16:54:38 +0200 Subject: [PATCH 14/28] fix appveyor and cpplint --- .gitmodules | 3 +++ appveyor.yml | 2 -- deps/styleguide | 1 + package.json | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) create mode 160000 deps/styleguide diff --git a/.gitmodules b/.gitmodules index 198dc21..c6bcac9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "deps/ncurses"] path = deps/ncurses url = git://ncurses.scripts.mit.edu/ncurses.git +[submodule "deps/styleguide"] + path = deps/styleguide + url = git://github.com/google/styleguide.git diff --git a/appveyor.yml b/appveyor.yml index 6ab0fc4..968ada9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,8 +7,6 @@ environment: # - nodejs_version: "0.8" mocha does not work on windows with v0.8 - nodejs_version: "0.10" - nodejs_version: "0.12" - -environment: REBUILD: true BDEBUG: true diff --git a/deps/styleguide b/deps/styleguide new file mode 160000 index 0000000..43d738a --- /dev/null +++ b/deps/styleguide @@ -0,0 +1 @@ +Subproject commit 43d738ab8bb0c797f78506945729946aacbab17d diff --git a/package.json b/package.json index 2c738fb..4d78ad3 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "prepublish": "npm run-script lint", - "lint": "cpplint.py --extensions=h,cc --filter=-runtime/printf include/* src/*", + "lint": "deps/styleguide/cpplint/cpplint.py --extensions=h,cc --filter=-runtime/printf include/* src/*", "test": "./node_modules/.bin/mocha tests/run --reporter min" }, "repository": { From 5f471181a8cfb47ebe1a32cb2ee72a04f8c7fa10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Mon, 8 Jun 2015 23:04:52 +0200 Subject: [PATCH 15/28] unix: added some features improved structure --- .travis.yml | 2 +- appveyor.yml | 4 +- binding.gyp | 24 +- include/ttyu.h | 4 + include/unix.h | 4 +- lib/export.js | 8 +- package.json | 2 +- src/{ => core}/ttyu.cc | 12 +- src/{ => core}/ttyu_event.cc | 0 src/{ => core}/utils.cc | 0 src/unix.cc | 521 ----------------------------------- src/unix/beep.cc | 30 ++ src/unix/clear.cc | 31 +++ src/unix/curses.cc | 223 +++++++++++++++ src/unix/emit.cc | 74 +++++ src/unix/goto.cc | 49 ++++ src/unix/main.cc | 34 +++ src/unix/mode.cc | 30 ++ src/unix/off.cc | 36 +++ src/unix/on.cc | 36 +++ src/unix/resize.cc | 59 ++++ src/unix/start.cc | 45 +++ src/unix/stop.cc | 43 +++ src/unix/utils.cc | 42 +++ src/unix/worker.cc | 118 ++++++++ src/unix/write.cc | 31 +++ src/{win.cc => win/main.cc} | 0 27 files changed, 919 insertions(+), 543 deletions(-) rename src/{ => core}/ttyu.cc (92%) rename src/{ => core}/ttyu_event.cc (100%) rename src/{ => core}/utils.cc (100%) delete mode 100644 src/unix.cc create mode 100644 src/unix/beep.cc create mode 100644 src/unix/clear.cc create mode 100644 src/unix/curses.cc create mode 100644 src/unix/emit.cc create mode 100644 src/unix/goto.cc create mode 100644 src/unix/main.cc create mode 100644 src/unix/mode.cc create mode 100644 src/unix/off.cc create mode 100644 src/unix/on.cc create mode 100644 src/unix/resize.cc create mode 100644 src/unix/start.cc create mode 100644 src/unix/stop.cc create mode 100644 src/unix/utils.cc create mode 100644 src/unix/worker.cc create mode 100644 src/unix/write.cc rename src/{win.cc => win/main.cc} (100%) diff --git a/.travis.yml b/.travis.yml index b2c3e4b..a2086f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: node_js os: - linux - osx -env: TTYU_NCURSES_REBUILD=true TTYU_BUILD_DEBUG=true TTYU_CODE_DEBUG=true +env: TTYU_NCURSES_REBUILD=true TTYU_BUILD_DEBUG=true node_js: - "0.8" - "0.10" diff --git a/appveyor.yml b/appveyor.yml index 968ada9..4e2711c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,8 +7,8 @@ environment: # - nodejs_version: "0.8" mocha does not work on windows with v0.8 - nodejs_version: "0.10" - nodejs_version: "0.12" - REBUILD: true - BDEBUG: true + TTYU_NCURSES_REBUILD: true + TTYU_BUILD_DEBUG: true platform: - x86 diff --git a/binding.gyp b/binding.gyp index d9a6745..9424fff 100644 --- a/binding.gyp +++ b/binding.gyp @@ -9,9 +9,9 @@ ], "sources": [ "deps/ee.c/ee.c", - "src/ttyu_event.cc", - "src/ttyu.cc", - "src/utils.cc" + "src/core/ttyu_event.cc", + "src/core/ttyu.cc", + "src/core/utils.cc" ], # pre install script @@ -30,7 +30,7 @@ "PLATFORM_WINDOWS" ], "sources": [ - "src/win.cc" + "src/win/main.cc" # TODO ] }, { # "OS!='win" "include_dirs": [ "../deps/ncurses" ], @@ -39,7 +39,21 @@ "library_dirs": [ "../deps/ncurses/lib/" ] }, "sources": [ - "src/unix.cc" + "src/unix/beep.cc", + "src/unix/clear.cc", + "src/unix/emit.cc", + "src/unix/goto.cc", + "src/unix/mode.cc", + "src/unix/off.cc", + "src/unix/on.cc", + "src/unix/resize.cc", + "src/unix/start.cc", + "src/unix/stop.cc", + "src/unix/write.cc", + "src/unix/main.cc", + "src/unix/utils.cc", + "src/unix/curses.cc", + "src/unix/worker.cc" ] }] ] diff --git a/include/ttyu.h b/include/ttyu.h index 1b0da74..4113069 100644 --- a/include/ttyu.h +++ b/include/ttyu.h @@ -138,11 +138,15 @@ class ttyu_js_c : public node::ObjectWrap { static NAN_METHOD(js_getheight); static NAN_METHOD(js_setwidth); static NAN_METHOD(js_setheight); + static NAN_METHOD(js_resize); static NAN_METHOD(js_mode); static NAN_METHOD(js_setx); static NAN_METHOD(js_getx); static NAN_METHOD(js_sety); static NAN_METHOD(js_gety); + static NAN_METHOD(js_goto); + static NAN_METHOD(js_beep); + static NAN_METHOD(js_clear); static NAN_METHOD(js_write); diff --git a/include/unix.h b/include/unix.h index 262b797..329ee2c 100644 --- a/include/unix.h +++ b/include/unix.h @@ -98,8 +98,8 @@ \ XX(WHICH_SHIFT, 0, TRUE) -TTYU_INLINE int ttyu_unix_which(int c); -TTYU_INLINE int ttyu_unix_key(int which); +int ttyu_unix_which(int c); +int ttyu_unix_key(int which); class ttyu_worker_c : public NanAsyncWorker { public: diff --git a/lib/export.js b/lib/export.js index 48ba3e9..6c56782 100644 --- a/lib/export.js +++ b/lib/export.js @@ -5,9 +5,13 @@ var DIRECT = [ "running", "width", "height", + "resize", "mode", "x", "y", + "goto", + "beep", + "clear", "start", "stop" ]; @@ -62,8 +66,8 @@ module.exports = function(ttyu_js_c) { } else if("set" + d in ttyu) { Object.defineProperty(ttyutil, d, { __proto__: null, - get: ttyu["set" + d], - set: ttyu["get" + d], + get: ttyu["get" + d], + set: ttyu["set" + d], configurable: false, enumerable: true, writeable: false diff --git a/package.json b/package.json index 4d78ad3..9e2cc0e 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "prepublish": "npm run-script lint", - "lint": "deps/styleguide/cpplint/cpplint.py --extensions=h,cc --filter=-runtime/printf include/* src/*", + "lint": "deps/styleguide/cpplint/cpplint.py --extensions=h,cc --filter=-runtime/printf include/* src/core/* src/unix/* src/win/*", "test": "./node_modules/.bin/mocha tests/run --reporter min" }, "repository": { diff --git a/src/ttyu.cc b/src/core/ttyu.cc similarity index 92% rename from src/ttyu.cc rename to src/core/ttyu.cc index f8bf683..f9e9abf 100644 --- a/src/ttyu.cc +++ b/src/core/ttyu.cc @@ -74,23 +74,17 @@ void ttyu_js_c::init(v8::Handle exports, EXPORT_METHOD(tpl, "getheight", js_getheight); EXPORT_METHOD(tpl, "setwidth", js_setwidth); EXPORT_METHOD(tpl, "setheight", js_setheight); + EXPORT_METHOD(tpl, "resize", js_resize); EXPORT_METHOD(tpl, "getmode", js_mode); EXPORT_METHOD(tpl, "setx", js_setx); EXPORT_METHOD(tpl, "getx", js_getx); EXPORT_METHOD(tpl, "sety", js_sety); EXPORT_METHOD(tpl, "gety", js_gety); - -/* - EXPORT_GET(tpl, "width", js_width); - EXPORT_GET(tpl, "height", js_height); - EXPORT_GET(tpl, "mode", js_mode); - EXPORT_GET(tpl, "colors", js_colors); - EXPORT_GETSET(tpl, "x", js_getx, js_setx); - EXPORT_GETSET(tpl, "y", js_gety, js_sety); EXPORT_METHOD(tpl, "goto", js_goto); - EXPORT_METHOD(tpl, "color", js_color); EXPORT_METHOD(tpl, "beep", js_beep); EXPORT_METHOD(tpl, "clear", js_clear); +/* + EXPORT_METHOD(tpl, "color", js_color); EXPORT_METHOD(tpl, "prepare", js_prepare);*/ module->Set(NanNew("exports"), tpl->GetFunction()); diff --git a/src/ttyu_event.cc b/src/core/ttyu_event.cc similarity index 100% rename from src/ttyu_event.cc rename to src/core/ttyu_event.cc diff --git a/src/utils.cc b/src/core/utils.cc similarity index 100% rename from src/utils.cc rename to src/core/utils.cc diff --git a/src/unix.cc b/src/unix.cc deleted file mode 100644 index de3258f..0000000 --- a/src/unix.cc +++ /dev/null @@ -1,521 +0,0 @@ -/* ttyutil - unix.cc - implements methods for unixy systems (see include/unix.h) - * https://github.com/clidejs/ttyutil - * - * Copyright Bernhard Bücherl - * - * 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. - */ -#include - -ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), mode(MODE_VT100) { - ee_init(&emitter, ttyu_ee_cb_call, ttyu_ee_compare); -} - -ttyu_js_c::~ttyu_js_c() { - running = FALSE; - stop = TRUE; - ee_destroy(&emitter); -} - -NAN_METHOD(ttyu_js_c::js_start) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - obj->running = TRUE; - obj->stop = FALSE; - obj->worker_run = TRUE; - obj->win = initscr(); - - uv_barrier_init(&obj->barrier, 3); - uv_mutex_init(&obj->emitlock); - uv_mutex_init(&obj->emitstacklock); - uv_mutex_init(&obj->ungetlock); - uv_cond_init(&obj->condition); - - uv_thread_create(&obj->curses_thread, ttyu_js_c::curses_thread_func, obj); - obj->check_queue(); - - uv_barrier_wait(&obj->barrier); - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::js_stop) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - obj->running = FALSE; - obj->stop = TRUE; - - uv_thread_join(&obj->curses_thread); - uv_mutex_destroy(&obj->emitlock); - uv_mutex_destroy(&obj->emitstacklock); - uv_mutex_destroy(&obj->ungetlock); - uv_cond_destroy(&obj->condition); - uv_barrier_destroy(&obj->barrier); - endwin(); - delwin(obj->win); - - DBG("window deleted"); - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::js_on) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - uv_mutex_lock(&obj->emitlock); - { - ee_on(&obj->emitter, args[0]->Int32Value(), - new NanCallback(v8::Local::Cast(args[1]))); - } - uv_mutex_unlock(&obj->emitlock); - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::js_off) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - uv_mutex_lock(&obj->emitlock); - { - ee_off(&obj->emitter, args[0]->Int32Value(), - new NanCallback(v8::Local::Cast(args[1]))); - } - uv_mutex_unlock(&obj->emitlock); - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::js_emit) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - int arg0 = args[0]->Int32Value(); - int arg1 = args[1]->Int32Value(); - int arg2 = args[2]->Int32Value(); - int arg3 = args[3]->Int32Value(); - int arg4 = args[4]->Int32Value(); - ttyu_event_t event; - switch (arg0) { - case EVENT_KEY: { - int c = -1; - if (arg2 & CTRL_CMD) { - c = KEY_COMMAND; - } else if (arg1 >= 65 && arg1 <= 90) { - if (arg2 & CTRL_SHIFT) { - c = arg1; // A-Z - } else { - c = arg1 + 32; // a-z - } - } else if (arg1 >= 48 && arg1 <= 57) { - c = arg1; // 0 - 9 - } else { - c = ttyu_unix_key(arg1); - } // TODO(@bbuecherl) v - ttyu_event_create_key(&event, arg2, " ", c, arg1); - } break; - case EVENT_MOUSEDOWN: - case EVENT_MOUSEUP: - case EVENT_MOUSEMOVE: { - ttyu_event_create_mouse(&event, arg0, arg1, arg2, arg3, arg4); - } break; - default: - // EVENT_NONE, EVENT_ERROR, EVENT_SIGNAL, EVENT_RESIZE, EVENT_MOUSEWHEEL, - // EVENT_MOUSEHWHEEL - event.type = EVENT_NONE; - break; - } - - if (event.type != EVENT_NONE) { - uv_mutex_lock(&obj->ungetlock); - { - obj->unget_stack.push(event); - } - uv_mutex_unlock(&obj->ungetlock); - } - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::js_write) { - NanScope(); - printf("%s", TTYU_TOSTRING(args[0])); - refresh(); - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::js_getwidth) { - NanScope(); - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - NanReturnValue(NanNew(w.ws_col)); -} - -NAN_METHOD(ttyu_js_c::js_getheight) { - NanScope(); - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - NanReturnValue(NanNew(w.ws_row)); -} - -NAN_METHOD(ttyu_js_c::js_setwidth) { - NanScope(); - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - resizeterm(args[0]->Int32Value(), w.ws_row); - NanReturnUndefined(); -} - -NAN_METHOD(ttyu_js_c::js_setheight) { - NanScope(); - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - resizeterm(w.ws_col, args[0]->Int32Value()); - NanReturnUndefined(); -} - -NAN_METHOD(ttyu_js_c::js_setx) { - NanScope(); - NanReturnUndefined(); -} - -NAN_METHOD(ttyu_js_c::js_getx) { - NanScope(); - NanReturnUndefined(); -} - -NAN_METHOD(ttyu_js_c::js_sety) { - NanScope(); - NanReturnUndefined(); -} - -NAN_METHOD(ttyu_js_c::js_gety) { - NanScope(); - NanReturnUndefined(); -} - -NAN_METHOD(ttyu_js_c::js_mode) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(obj->mode)); -} - -void ttyu_js_c::check_queue() { - if (running && !stop) { - NanAsyncQueueWorker(new ttyu_worker_c(this)); - } -} - -void ttyu_worker_c::Execute() { - uv_mutex_lock(&obj->emitstacklock); - { - if (obj->worker_run) { - obj->worker_run = FALSE; - uv_barrier_wait(&obj->barrier); - } - - while (obj->emit_stack.size() == 0) { - uv_cond_wait(&obj->condition, &obj->emitstacklock); - } - - SDBG("::Execute %zu", obj->emit_stack.size()); - - // copy stack into emit_worker and clear stack - std::copy(obj->emit_stack.begin(), obj->emit_stack.end(), - std::back_inserter(emit_stack)); - obj->emit_stack.clear(); - } - uv_mutex_unlock(&obj->emitstacklock); -} - -void ttyu_worker_c::HandleOKCallback() { - NanScope(); - for (std::vector::size_type i = 0; - i < emit_stack.size(); ++i) { - ttyu_event_t event = emit_stack[i]; - SDBG("::HandleOKCallback %d %d", i, event.type); - - if (ee_count(&obj->emitter, event.type) == 0 || - event.type == EVENT_NONE) { - continue; // fast skip - } - - v8::Local jsobj = NanNew(); - switch (event.type) { - case EVENT_RESIZE: - jsobj->Set(NanNew("type"), EVENTSTRING_RESIZE); - break; - case EVENT_KEY: - jsobj->Set(NanNew("type"), EVENTSTRING_KEY); - jsobj->Set(NanNew("ctrl"), - NanNew(event.key->ctrl)); - jsobj->Set(NanNew("char"), - NanNew(event.key->c)); - jsobj->Set(NanNew("code"), - NanNew(event.key->code)); - jsobj->Set(NanNew("which"), - NanNew(event.key->which)); - break; - case EVENT_MOUSEDOWN: - case EVENT_MOUSEUP: - case EVENT_MOUSEMOVE: - case EVENT_MOUSEWHEEL: - case EVENT_MOUSEHWHEEL: - if (event.type == EVENT_MOUSEDOWN) { - jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEDOWN); - } else if (event.type == EVENT_MOUSEUP) { - jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEUP); - } else if (event.type == EVENT_MOUSEMOVE) { - jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEMOVE); - } else if (event.type == EVENT_MOUSEWHEEL) { - jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEWHEEL); - } else if (event.type == EVENT_MOUSEHWHEEL) { - jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEHWHEEL); - } - jsobj->Set(NanNew("button"), - NanNew(event.mouse->button)); - jsobj->Set(NanNew("x"), - NanNew(event.mouse->x)); - jsobj->Set(NanNew("y"), - NanNew(event.mouse->y)); - jsobj->Set(NanNew("ctrl"), - NanNew(event.mouse->ctrl)); - break; - default: // EVENT_ERROR, EVENT_SIGNAL - jsobj->Set(NanNew("type"), EVENTSTRING_ERROR); - jsobj->Set(NanNew("error"), NanError("...")); - event.type = EVENT_ERROR; - break; - } - - ee_emit(&obj->emitter, event.type, jsobj); - } - emit_stack.clear(); - obj->check_queue(); -} - -int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { - ttyu_js_c *obj = static_cast(that); - - int c = wgetch(win); - MEVENT mev; - ttyu_event_t event; - event.type = EVENT_NONE; - - if (c == ERR) { - uv_mutex_lock(&obj->ungetlock); - if (!obj->unget_stack.empty()) { - ttyu_event_t ev = obj->unget_stack.front(); - obj->unget_stack.pop(); - uv_mutex_unlock(&obj->ungetlock); - switch (ev.type) { - case EVENT_KEY: - ungetch(ev.key->code); - break; - case EVENT_MOUSEUP: - case EVENT_MOUSEDOWN: - case EVENT_MOUSEMOVE: - mev.x = ev.mouse->x; - mev.y = ev.mouse->y; - mev.bstate = 0; - - if (ev.mouse->ctrl & CTRL_ALT) { mev.bstate |= BUTTON_ALT; } - if (ev.mouse->ctrl & CTRL_CTRL) { mev.bstate |= BUTTON_CTRL; } - if (ev.mouse->ctrl & CTRL_SHIFT) { mev.bstate |= BUTTON_SHIFT; } - - if (ev.type == EVENT_MOUSEMOVE) { - mev.bstate |= REPORT_MOUSE_POSITION; - } else if (ev.type == EVENT_MOUSEUP) { - if (ev.mouse->button == MOUSE_LEFT) { - mev.bstate |= BUTTON1_RELEASED; - } else if (ev.mouse->button == MOUSE_LEFT2) { - mev.bstate |= BUTTON2_RELEASED; - } else if (ev.mouse->button == MOUSE_LEFT3) { - mev.bstate |= BUTTON3_RELEASED; - } else if (ev.mouse->button == MOUSE_LEFT4) { - mev.bstate |= BUTTON4_RELEASED; - } else if (ev.mouse->button == MOUSE_RIGHT) { -#if NCURSES_MOUSE_VERSION > 1 - mev.bstate |= BUTTON5_RELEASED; -#else - mev.bstate |= BUTTON4_RELEASED; -#endif - } - } else if (ev.type == EVENT_MOUSEDOWN) { - if (ev.mouse->button == MOUSE_LEFT) { - mev.bstate |= BUTTON1_PRESSED; - } else if (ev.mouse->button == MOUSE_LEFT2) { - mev.bstate |= BUTTON2_PRESSED; - } else if (ev.mouse->button == MOUSE_LEFT3) { - mev.bstate |= BUTTON3_PRESSED; - } else if (ev.mouse->button == MOUSE_LEFT4) { - mev.bstate |= BUTTON4_PRESSED; - } else if (ev.mouse->button == MOUSE_RIGHT) { -#if NCURSES_MOUSE_VERSION > 1 - mev.bstate |= BUTTON5_PRESSED; -#else - mev.bstate |= BUTTON4_PRESSED; -#endif - } - } - ungetmouse(&mev); - break; - case EVENT_MOUSEWHEEL: - case EVENT_MOUSEHWHEEL: - // TODO(@bbuecherl) - break; - default: - // EVENT_NONE, EVENT_ERROR, EVENT_SIGNAL, EVENT_RESIZE - break; - } - } else { - uv_mutex_unlock(&obj->ungetlock); - } - return 0; - } else if (c == KEY_RESIZE) { - ttyu_event_create_resize(&event); - } else if (c == KEY_MOUSE) { - if (getmouse(&mev) == OK) { - ttyu_event_create_mouse(&event, EVENT_ERROR, 0, mev.x, mev.y, 0); - - // add button control key sequences if possible - if (mev.bstate & BUTTON_SHIFT) { event.mouse->ctrl |= CTRL_SHIFT; } - if (mev.bstate & BUTTON_CTRL) { event.mouse->ctrl |= CTRL_CTRL; } - if (mev.bstate & BUTTON_ALT) { event.mouse->ctrl |= CTRL_ALT; } - - // convert button codes and mev type - if (mev.bstate & REPORT_MOUSE_POSITION) { - event.type = EVENT_MOUSEMOVE; - } else if (mev.bstate & BUTTON1_RELEASED) { - event.mouse->button = MOUSE_LEFT; - event.type = EVENT_MOUSEUP; - } else if (mev.bstate & BUTTON1_PRESSED) { - event.mouse->button = MOUSE_LEFT; - event.type = EVENT_MOUSEDOWN; - } else if (mev.bstate & BUTTON2_RELEASED) { - event.mouse->button = MOUSE_LEFT2; - event.type = EVENT_MOUSEUP; - } else if (mev.bstate & BUTTON2_PRESSED) { - event.mouse->button = MOUSE_LEFT2; - event.type = EVENT_MOUSEDOWN; - } else if (mev.bstate & BUTTON3_RELEASED) { - event.mouse->button = MOUSE_LEFT3; - event.type = EVENT_MOUSEUP; - } else if (mev.bstate & BUTTON3_PRESSED) { - event.mouse->button = MOUSE_LEFT3; - event.type = EVENT_MOUSEDOWN; - } else { -#if NCURSES_MOUSE_VERSION > 1 - if (mev.bstate & BUTTON4_RELEASED) { - event.mouse->button = MOUSE_LEFT4; - event.type = EVENT_MOUSEUP; - } else if (mev.bstate & BUTTON4_PRESSED) { - event.mouse->button = MOUSE_LEFT4; - event.type = EVENT_MOUSEDOWN; - } else if (mev.bstate & BUTTON5_RELEASED) { - event.mouse->button = MOUSE_RIGHT; - event.type = EVENT_MOUSEUP; - } else if (mev.bstate & BUTTON5_PRESSED) { - event.mouse->button = MOUSE_RIGHT; - event.type = EVENT_MOUSEDOWN; - } -#else - if (mev.bstate & BUTTON4_RELEASED) { - event.mouse->button = MOUSE_RIGHT; - event.type = EVENT_MOUSEUP; - } else if (mev.bstate & BUTTON4_PRESSED) { - event.mouse->button = MOUSE_RIGHT; - event.type = EVENT_MOUSEDOWN; - } -#endif - } - if (event.type == EVENT_ERROR) { - // uncaught mouse event - event.type = EVENT_NONE; - } else { - obj->mode = MODE_VT102; - } - } else { - // bad mouse event - event.type = EVENT_NONE; - } - } else { - char *ch = const_cast(keyname(c)); - int ctrl = CTRL_NULL; - int which = WHICH_UNKNOWN; - - if (c >= 48 && c <= 57) { - which = c; // WHICH_CHAR0 to WHICH_CHAR9 - } else if (c >= 65 && c <= 90) { - ctrl |= CTRL_SHIFT; - which = c; // WHICH_CHARA to WHICH_CHARZ - } else if (c >= 97 && c <= 122) { - which = c - 32; // WHICH_CHARA to WHICH_CHARZ - } else if (c == KEY_COMMAND) { - ctrl |= CTRL_CMD; - } else if (c == KEY_SCOMMAND) { - ctrl |= CTRL_CMD | CTRL_SHIFT; - } else { - which = ttyu_unix_which(c); - if (sizeof(ch) > 4 && ch[0] == '^') { - ctrl |= CTRL_CTRL; - } - } - ttyu_event_create_key(&event, ctrl, ch, c, which); - } - - if (event.type != EVENT_NONE) { - uv_mutex_lock(&obj->emitstacklock); - { - obj->emit_stack.push_back(event); - uv_cond_signal(&obj->condition); - } - uv_mutex_unlock(&obj->emitstacklock); - } - return 0; -} - -void ttyu_js_c::curses_thread_func(void *that) { - ttyu_js_c *obj = static_cast(that); - - noecho(); - cbreak(); - keypad(obj->win, TRUE); - mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); - nodelay(obj->win, TRUE); - mouseinterval(FALSE); - - uv_barrier_wait(&obj->barrier); - - while (obj->running && !obj->stop) { - use_window(obj->win, curses_threaded_func, that); - usleep(100); - } -} - -TTYU_INLINE int ttyu_unix_key(int which) { - #define XXKEY(w, key, shift) if (w == which) { \ - return key; \ - } - TTYU_UNIX_KW(XXKEY); - #undef XXKEY - return WHICH_UNKNOWN; -} - -TTYU_INLINE int ttyu_unix_which(int key) { - #define XXWHICH(which, k, shift) if (k == key) { \ - return which; \ - } - TTYU_UNIX_KW(XXWHICH); - #undef XXWHICH - return WHICH_UNKNOWN; -} diff --git a/src/unix/beep.cc b/src/unix/beep.cc new file mode 100644 index 0000000..3f3bb2b --- /dev/null +++ b/src/unix/beep.cc @@ -0,0 +1,30 @@ +/* ttyutil - unix/beep.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_beep) { + NanScope(); + beep(); + NanReturnThis(); +} diff --git a/src/unix/clear.cc b/src/unix/clear.cc new file mode 100644 index 0000000..547fd86 --- /dev/null +++ b/src/unix/clear.cc @@ -0,0 +1,31 @@ +/* ttyutil - unix/clear.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_clear) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + werase(obj->win); + NanReturnThis(); +} diff --git a/src/unix/curses.cc b/src/unix/curses.cc new file mode 100644 index 0000000..8f86668 --- /dev/null +++ b/src/unix/curses.cc @@ -0,0 +1,223 @@ +/* ttyutil - unix/curses.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { + ttyu_js_c *obj = static_cast(that); + + int c = wgetch(win); + MEVENT mev; + ttyu_event_t event; + event.type = EVENT_NONE; + + if (c == ERR) { + uv_mutex_lock(&obj->ungetlock); + if (!obj->unget_stack.empty()) { + ttyu_event_t ev = obj->unget_stack.front(); + obj->unget_stack.pop(); + uv_mutex_unlock(&obj->ungetlock); + switch (ev.type) { + case EVENT_KEY: + ungetch(ev.key->code); + break; + case EVENT_MOUSEUP: + case EVENT_MOUSEDOWN: + case EVENT_MOUSEMOVE: + mev.x = ev.mouse->x; + mev.y = ev.mouse->y; + mev.bstate = 0; + + if (ev.mouse->ctrl & CTRL_ALT) { mev.bstate |= BUTTON_ALT; } + if (ev.mouse->ctrl & CTRL_CTRL) { mev.bstate |= BUTTON_CTRL; } + if (ev.mouse->ctrl & CTRL_SHIFT) { mev.bstate |= BUTTON_SHIFT; } + + if (ev.type == EVENT_MOUSEMOVE) { + mev.bstate |= REPORT_MOUSE_POSITION; + } else if (ev.type == EVENT_MOUSEUP) { + if (ev.mouse->button == MOUSE_LEFT) { + mev.bstate |= BUTTON1_RELEASED; + } else if (ev.mouse->button == MOUSE_LEFT2) { + mev.bstate |= BUTTON2_RELEASED; + } else if (ev.mouse->button == MOUSE_LEFT3) { + mev.bstate |= BUTTON3_RELEASED; + } else if (ev.mouse->button == MOUSE_LEFT4) { + mev.bstate |= BUTTON4_RELEASED; + } else if (ev.mouse->button == MOUSE_RIGHT) { +#if NCURSES_MOUSE_VERSION > 1 + mev.bstate |= BUTTON5_RELEASED; +#else + mev.bstate |= BUTTON4_RELEASED; +#endif + } + } else if (ev.type == EVENT_MOUSEDOWN) { + if (ev.mouse->button == MOUSE_LEFT) { + mev.bstate |= BUTTON1_PRESSED; + } else if (ev.mouse->button == MOUSE_LEFT2) { + mev.bstate |= BUTTON2_PRESSED; + } else if (ev.mouse->button == MOUSE_LEFT3) { + mev.bstate |= BUTTON3_PRESSED; + } else if (ev.mouse->button == MOUSE_LEFT4) { + mev.bstate |= BUTTON4_PRESSED; + } else if (ev.mouse->button == MOUSE_RIGHT) { +#if NCURSES_MOUSE_VERSION > 1 + mev.bstate |= BUTTON5_PRESSED; +#else + mev.bstate |= BUTTON4_PRESSED; +#endif + } + } + ungetmouse(&mev); + break; + case EVENT_MOUSEWHEEL: + case EVENT_MOUSEHWHEEL: + // TODO(@bbuecherl) + break; + default: + // EVENT_NONE, EVENT_ERROR, EVENT_SIGNAL, EVENT_RESIZE + break; + } + } else { + uv_mutex_unlock(&obj->ungetlock); + } + return 0; + } else if (c == KEY_RESIZE) { + ttyu_event_create_resize(&event); + } else if (c == KEY_MOUSE) { + if (getmouse(&mev) == OK) { + ttyu_event_create_mouse(&event, EVENT_ERROR, 0, mev.x, mev.y, 0); + + // add button control key sequences if possible + if (mev.bstate & BUTTON_SHIFT) { event.mouse->ctrl |= CTRL_SHIFT; } + if (mev.bstate & BUTTON_CTRL) { event.mouse->ctrl |= CTRL_CTRL; } + if (mev.bstate & BUTTON_ALT) { event.mouse->ctrl |= CTRL_ALT; } + + // convert button codes and mev type + if (mev.bstate & REPORT_MOUSE_POSITION) { + event.type = EVENT_MOUSEMOVE; + } else if (mev.bstate & BUTTON1_RELEASED) { + event.mouse->button = MOUSE_LEFT; + event.type = EVENT_MOUSEUP; + } else if (mev.bstate & BUTTON1_PRESSED) { + event.mouse->button = MOUSE_LEFT; + event.type = EVENT_MOUSEDOWN; + } else if (mev.bstate & BUTTON2_RELEASED) { + event.mouse->button = MOUSE_LEFT2; + event.type = EVENT_MOUSEUP; + } else if (mev.bstate & BUTTON2_PRESSED) { + event.mouse->button = MOUSE_LEFT2; + event.type = EVENT_MOUSEDOWN; + } else if (mev.bstate & BUTTON3_RELEASED) { + event.mouse->button = MOUSE_LEFT3; + event.type = EVENT_MOUSEUP; + } else if (mev.bstate & BUTTON3_PRESSED) { + event.mouse->button = MOUSE_LEFT3; + event.type = EVENT_MOUSEDOWN; + } else { +#if NCURSES_MOUSE_VERSION > 1 + if (mev.bstate & BUTTON4_RELEASED) { + event.mouse->button = MOUSE_LEFT4; + event.type = EVENT_MOUSEUP; + } else if (mev.bstate & BUTTON4_PRESSED) { + event.mouse->button = MOUSE_LEFT4; + event.type = EVENT_MOUSEDOWN; + } else if (mev.bstate & BUTTON5_RELEASED) { + event.mouse->button = MOUSE_RIGHT; + event.type = EVENT_MOUSEUP; + } else if (mev.bstate & BUTTON5_PRESSED) { + event.mouse->button = MOUSE_RIGHT; + event.type = EVENT_MOUSEDOWN; + } +#else + if (mev.bstate & BUTTON4_RELEASED) { + event.mouse->button = MOUSE_RIGHT; + event.type = EVENT_MOUSEUP; + } else if (mev.bstate & BUTTON4_PRESSED) { + event.mouse->button = MOUSE_RIGHT; + event.type = EVENT_MOUSEDOWN; + } +#endif + } + if (event.type == EVENT_ERROR) { + // uncaught mouse event + event.type = EVENT_NONE; + } else { + obj->mode = MODE_VT102; + } + } else { + // bad mouse event + event.type = EVENT_NONE; + } + } else { + char *ch = const_cast(keyname(c)); + int ctrl = CTRL_NULL; + int which = WHICH_UNKNOWN; + + if (c >= 48 && c <= 57) { + which = c; // WHICH_CHAR0 to WHICH_CHAR9 + } else if (c >= 65 && c <= 90) { + ctrl |= CTRL_SHIFT; + which = c; // WHICH_CHARA to WHICH_CHARZ + } else if (c >= 97 && c <= 122) { + which = c - 32; // WHICH_CHARA to WHICH_CHARZ + } else if (c == KEY_COMMAND) { + ctrl |= CTRL_CMD; + } else if (c == KEY_SCOMMAND) { + ctrl |= CTRL_CMD | CTRL_SHIFT; + } else { + which = ttyu_unix_which(c); + if (sizeof(ch) > 4 && ch[0] == '^') { + ctrl |= CTRL_CTRL; + } + } + ttyu_event_create_key(&event, ctrl, ch, c, which); + } + + if (event.type != EVENT_NONE) { + uv_mutex_lock(&obj->emitstacklock); + { + obj->emit_stack.push_back(event); + uv_cond_signal(&obj->condition); + } + uv_mutex_unlock(&obj->emitstacklock); + } + return 0; +} + +void ttyu_js_c::curses_thread_func(void *that) { + ttyu_js_c *obj = static_cast(that); + + noecho(); + cbreak(); + keypad(obj->win, TRUE); + mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); + nodelay(obj->win, TRUE); + mouseinterval(FALSE); + + uv_barrier_wait(&obj->barrier); + + while (obj->running && !obj->stop) { + use_window(obj->win, curses_threaded_func, that); + usleep(100); + } +} diff --git a/src/unix/emit.cc b/src/unix/emit.cc new file mode 100644 index 0000000..2341cf0 --- /dev/null +++ b/src/unix/emit.cc @@ -0,0 +1,74 @@ +/* ttyutil - unix/emit.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_emit) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + int arg0 = args[0]->Int32Value(); + int arg1 = args[1]->Int32Value(); + int arg2 = args[2]->Int32Value(); + int arg3 = args[3]->Int32Value(); + int arg4 = args[4]->Int32Value(); + ttyu_event_t event; + switch (arg0) { + case EVENT_KEY: { + int c = -1; + char ch = 0x20; + if (arg2 & CTRL_CMD) { + c = KEY_COMMAND; + } else if (arg1 >= 65 && arg1 <= 90) { + if (arg2 & CTRL_SHIFT) { + c = arg1; // A-Z + } else { + c = arg1 + 32; // a-z + } + } else if (arg1 >= 48 && arg1 <= 57) { + c = arg1; // 0 - 9 + } else { + c = ttyu_unix_key(arg1); + } // TODO(@bbuecherl) v + ttyu_event_create_key(&event, arg2, &ch, c, arg1); + } break; + case EVENT_MOUSEDOWN: + case EVENT_MOUSEUP: + case EVENT_MOUSEMOVE: { + ttyu_event_create_mouse(&event, arg0, arg1, arg2, arg3, arg4); + } break; + default: + // EVENT_NONE, EVENT_ERROR, EVENT_SIGNAL, EVENT_RESIZE, EVENT_MOUSEWHEEL, + // EVENT_MOUSEHWHEEL + event.type = EVENT_NONE; + break; + } + + if (event.type != EVENT_NONE) { + uv_mutex_lock(&obj->ungetlock); + { + obj->unget_stack.push(event); + } + uv_mutex_unlock(&obj->ungetlock); + } + NanReturnThis(); +} diff --git a/src/unix/goto.cc b/src/unix/goto.cc new file mode 100644 index 0000000..b65bcdc --- /dev/null +++ b/src/unix/goto.cc @@ -0,0 +1,49 @@ +/* ttyutil - unix/goto.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_setx) { + NanScope(); + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_getx) { + NanScope(); + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_sety) { + NanScope(); + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_gety) { + NanScope(); + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_goto) { + NanScope(); + NanReturnThis(); +} diff --git a/src/unix/main.cc b/src/unix/main.cc new file mode 100644 index 0000000..bbdfe71 --- /dev/null +++ b/src/unix/main.cc @@ -0,0 +1,34 @@ +/* ttyutil - unix/main.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), mode(MODE_VT100) { + ee_init(&emitter, ttyu_ee_cb_call, ttyu_ee_compare); +} + +ttyu_js_c::~ttyu_js_c() { + running = FALSE; + stop = TRUE; + ee_destroy(&emitter); +} diff --git a/src/unix/mode.cc b/src/unix/mode.cc new file mode 100644 index 0000000..0c77c10 --- /dev/null +++ b/src/unix/mode.cc @@ -0,0 +1,30 @@ +/* ttyutil - unix/mode.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_mode) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(obj->mode)); +} diff --git a/src/unix/off.cc b/src/unix/off.cc new file mode 100644 index 0000000..2b5b4e1 --- /dev/null +++ b/src/unix/off.cc @@ -0,0 +1,36 @@ +/* ttyutil - unix/off.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_off) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + uv_mutex_lock(&obj->emitlock); + { + ee_off(&obj->emitter, args[0]->Int32Value(), + new NanCallback(v8::Local::Cast(args[1]))); + } + uv_mutex_unlock(&obj->emitlock); + NanReturnThis(); +} diff --git a/src/unix/on.cc b/src/unix/on.cc new file mode 100644 index 0000000..68b8c84 --- /dev/null +++ b/src/unix/on.cc @@ -0,0 +1,36 @@ +/* ttyutil - unix/on.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_on) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + uv_mutex_lock(&obj->emitlock); + { + ee_on(&obj->emitter, args[0]->Int32Value(), + new NanCallback(v8::Local::Cast(args[1]))); + } + uv_mutex_unlock(&obj->emitlock); + NanReturnThis(); +} diff --git a/src/unix/resize.cc b/src/unix/resize.cc new file mode 100644 index 0000000..c822e3c --- /dev/null +++ b/src/unix/resize.cc @@ -0,0 +1,59 @@ +/* ttyutil - unix/resize.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_getwidth) { + NanScope(); + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + NanReturnValue(NanNew(w.ws_col)); +} + +NAN_METHOD(ttyu_js_c::js_getheight) { + NanScope(); + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + NanReturnValue(NanNew(w.ws_row)); +} + +NAN_METHOD(ttyu_js_c::js_setwidth) { + NanScope(); + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + resizeterm(args[0]->Int32Value(), w.ws_row); + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_setheight) { + NanScope(); + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + resizeterm(w.ws_col, args[0]->Int32Value()); + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_resize) { + NanScope(); + NanReturnThis(); +} diff --git a/src/unix/start.cc b/src/unix/start.cc new file mode 100644 index 0000000..f222419 --- /dev/null +++ b/src/unix/start.cc @@ -0,0 +1,45 @@ +/* ttyutil - unix/start.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_start) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + obj->running = TRUE; + obj->stop = FALSE; + obj->worker_run = TRUE; + obj->win = initscr(); + + uv_barrier_init(&obj->barrier, 3); + uv_mutex_init(&obj->emitlock); + uv_mutex_init(&obj->emitstacklock); + uv_mutex_init(&obj->ungetlock); + uv_cond_init(&obj->condition); + + uv_thread_create(&obj->curses_thread, ttyu_js_c::curses_thread_func, obj); + obj->check_queue(); + + uv_barrier_wait(&obj->barrier); + NanReturnThis(); +} diff --git a/src/unix/stop.cc b/src/unix/stop.cc new file mode 100644 index 0000000..c648c8d --- /dev/null +++ b/src/unix/stop.cc @@ -0,0 +1,43 @@ +/* ttyutil - unix/stop.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_stop) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + obj->running = FALSE; + obj->stop = TRUE; + + uv_thread_join(&obj->curses_thread); + uv_mutex_destroy(&obj->emitlock); + uv_mutex_destroy(&obj->emitstacklock); + uv_mutex_destroy(&obj->ungetlock); + uv_cond_destroy(&obj->condition); + uv_barrier_destroy(&obj->barrier); + endwin(); + delwin(obj->win); + + DBG("window deleted"); + NanReturnThis(); +} diff --git a/src/unix/utils.cc b/src/unix/utils.cc new file mode 100644 index 0000000..97c6b68 --- /dev/null +++ b/src/unix/utils.cc @@ -0,0 +1,42 @@ +/* ttyutil - unix/utils.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +int ttyu_unix_key(int which) { + #define XXKEY(w, key, shift) if (w == which) { \ + return key; \ + } + TTYU_UNIX_KW(XXKEY); + #undef XXKEY + return WHICH_UNKNOWN; +} + +int ttyu_unix_which(int key) { + #define XXWHICH(which, k, shift) if (k == key) { \ + return which; \ + } + TTYU_UNIX_KW(XXWHICH); + #undef XXWHICH + return WHICH_UNKNOWN; +} diff --git a/src/unix/worker.cc b/src/unix/worker.cc new file mode 100644 index 0000000..46766f5 --- /dev/null +++ b/src/unix/worker.cc @@ -0,0 +1,118 @@ +/* ttyutil - unix/worker.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +void ttyu_js_c::check_queue() { + if (running && !stop) { + NanAsyncQueueWorker(new ttyu_worker_c(this)); + } +} + +void ttyu_worker_c::Execute() { + uv_mutex_lock(&obj->emitstacklock); + { + if (obj->worker_run) { + obj->worker_run = FALSE; + uv_barrier_wait(&obj->barrier); + } + + while (obj->emit_stack.size() == 0) { + uv_cond_wait(&obj->condition, &obj->emitstacklock); + } + + SDBG("::Execute %zu", obj->emit_stack.size()); + + // copy stack into emit_worker and clear stack + std::copy(obj->emit_stack.begin(), obj->emit_stack.end(), + std::back_inserter(emit_stack)); + obj->emit_stack.clear(); + } + uv_mutex_unlock(&obj->emitstacklock); +} + +void ttyu_worker_c::HandleOKCallback() { + NanScope(); + for (std::vector::size_type i = 0; + i < emit_stack.size(); ++i) { + ttyu_event_t event = emit_stack[i]; + SDBG("::HandleOKCallback %d %d", i, event.type); + + if (ee_count(&obj->emitter, event.type) == 0 || + event.type == EVENT_NONE) { + continue; // fast skip + } + + v8::Local jsobj = NanNew(); + switch (event.type) { + case EVENT_RESIZE: + jsobj->Set(NanNew("type"), EVENTSTRING_RESIZE); + break; + case EVENT_KEY: + jsobj->Set(NanNew("type"), EVENTSTRING_KEY); + jsobj->Set(NanNew("ctrl"), + NanNew(event.key->ctrl)); + jsobj->Set(NanNew("char"), + NanNew(event.key->c)); + jsobj->Set(NanNew("code"), + NanNew(event.key->code)); + jsobj->Set(NanNew("which"), + NanNew(event.key->which)); + break; + case EVENT_MOUSEDOWN: + case EVENT_MOUSEUP: + case EVENT_MOUSEMOVE: + case EVENT_MOUSEWHEEL: + case EVENT_MOUSEHWHEEL: + if (event.type == EVENT_MOUSEDOWN) { + jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEDOWN); + } else if (event.type == EVENT_MOUSEUP) { + jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEUP); + } else if (event.type == EVENT_MOUSEMOVE) { + jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEMOVE); + } else if (event.type == EVENT_MOUSEWHEEL) { + jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEWHEEL); + } else if (event.type == EVENT_MOUSEHWHEEL) { + jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEHWHEEL); + } + jsobj->Set(NanNew("button"), + NanNew(event.mouse->button)); + jsobj->Set(NanNew("x"), + NanNew(event.mouse->x)); + jsobj->Set(NanNew("y"), + NanNew(event.mouse->y)); + jsobj->Set(NanNew("ctrl"), + NanNew(event.mouse->ctrl)); + break; + default: // EVENT_ERROR, EVENT_SIGNAL + jsobj->Set(NanNew("type"), EVENTSTRING_ERROR); + jsobj->Set(NanNew("error"), NanError("...")); + event.type = EVENT_ERROR; + break; + } + + ee_emit(&obj->emitter, event.type, jsobj); + } + emit_stack.clear(); + obj->check_queue(); +} diff --git a/src/unix/write.cc b/src/unix/write.cc new file mode 100644 index 0000000..32e0a75 --- /dev/null +++ b/src/unix/write.cc @@ -0,0 +1,31 @@ +/* ttyutil - unix/write.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_write) { + NanScope(); + printf("%s", TTYU_TOSTRING(args[0])); + refresh(); + NanReturnThis(); +} diff --git a/src/win.cc b/src/win/main.cc similarity index 100% rename from src/win.cc rename to src/win/main.cc From 99834dfee3de180d4082506dad3b13d9f38567a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Tue, 9 Jun 2015 19:21:53 +0200 Subject: [PATCH 16/28] structured windows implementation --- binding.gyp | 19 +- package.json | 3 +- src/core/{utils.cc => utilities.cc} | 0 src/unix/goto.cc | 5 + src/unix/resize.cc | 5 +- src/win/beep.cc | 30 +++ src/win/clear.cc | 30 +++ src/win/emit.cc | 106 ++++++++ src/win/goto.cc | 54 ++++ src/win/main.cc | 383 +--------------------------- src/win/mode.cc | 29 +++ src/win/off.cc | 34 +++ src/win/on.cc | 34 +++ src/win/resize.cc | 54 ++++ src/win/start.cc | 58 +++++ src/win/stop.cc | 35 +++ src/win/utils.cc | 105 ++++++++ src/win/worker.cc | 170 ++++++++++++ src/win/write.cc | 30 +++ 19 files changed, 795 insertions(+), 389 deletions(-) rename src/core/{utils.cc => utilities.cc} (100%) create mode 100644 src/win/beep.cc create mode 100644 src/win/clear.cc create mode 100644 src/win/emit.cc create mode 100644 src/win/goto.cc create mode 100644 src/win/mode.cc create mode 100644 src/win/off.cc create mode 100644 src/win/on.cc create mode 100644 src/win/resize.cc create mode 100644 src/win/start.cc create mode 100644 src/win/stop.cc create mode 100644 src/win/utils.cc create mode 100644 src/win/worker.cc create mode 100644 src/win/write.cc diff --git a/binding.gyp b/binding.gyp index 9424fff..a84bc13 100644 --- a/binding.gyp +++ b/binding.gyp @@ -11,7 +11,7 @@ "deps/ee.c/ee.c", "src/core/ttyu_event.cc", "src/core/ttyu.cc", - "src/core/utils.cc" + "src/core/utilities.cc" ], # pre install script @@ -19,7 +19,7 @@ { "action_name": "preinstall", "inputs": [ "tools/build.js" ], - "outputs": [ "" ], + "outputs": [ "include/generated.h" ], "action": [ "node", "tools/build.js" ] } ], @@ -30,7 +30,20 @@ "PLATFORM_WINDOWS" ], "sources": [ - "src/win/main.cc" # TODO + "src/win/beep.cc", + "src/win/clear.cc", + "src/win/emit.cc", + "src/win/goto.cc", + "src/win/mode.cc", + "src/win/off.cc", + "src/win/on.cc", + "src/win/resize.cc", + "src/win/start.cc", + "src/win/stop.cc", + "src/win/write.cc", + "src/win/main.cc", + "src/win/utils.cc", + "src/win/worker.cc" ] }, { # "OS!='win" "include_dirs": [ "../deps/ncurses" ], diff --git a/package.json b/package.json index 9e2cc0e..1354025 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,7 @@ "description": "cross-platform terminal utilities", "main": "index.js", "scripts": { - "prepublish": "npm run-script lint", - "lint": "deps/styleguide/cpplint/cpplint.py --extensions=h,cc --filter=-runtime/printf include/* src/core/* src/unix/* src/win/*", + "lint": "./deps/styleguide/cpplint/cpplint.py --extensions=h,cc --filter=-runtime/printf include/* src/core/* src/unix/* src/win/*", "test": "./node_modules/.bin/mocha tests/run --reporter min" }, "repository": { diff --git a/src/core/utils.cc b/src/core/utilities.cc similarity index 100% rename from src/core/utils.cc rename to src/core/utilities.cc diff --git a/src/unix/goto.cc b/src/unix/goto.cc index b65bcdc..c543222 100644 --- a/src/unix/goto.cc +++ b/src/unix/goto.cc @@ -25,25 +25,30 @@ NAN_METHOD(ttyu_js_c::js_setx) { NanScope(); + // TODO(@bbuecherl) NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_getx) { NanScope(); + // TODO(@bbuecherl) NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_sety) { NanScope(); + // TODO(@bbuecherl) NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_gety) { NanScope(); + // TODO(@bbuecherl) NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_goto) { NanScope(); + // TODO(@bbuecherl) NanReturnThis(); } diff --git a/src/unix/resize.cc b/src/unix/resize.cc index c822e3c..9f0e4d7 100644 --- a/src/unix/resize.cc +++ b/src/unix/resize.cc @@ -54,6 +54,7 @@ NAN_METHOD(ttyu_js_c::js_setheight) { } NAN_METHOD(ttyu_js_c::js_resize) { - NanScope(); - NanReturnThis(); + NanScope(); + resizeterm(args[0]->Int32Value(), args[1]->Int32Value()); + NanReturnThis(); } diff --git a/src/win/beep.cc b/src/win/beep.cc new file mode 100644 index 0000000..a35d88a --- /dev/null +++ b/src/win/beep.cc @@ -0,0 +1,30 @@ +/* ttyutil - win/beep.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_beep) { + NanScope(); + // TODO(@bbuecherl) + NanReturnThis(); +} diff --git a/src/win/clear.cc b/src/win/clear.cc new file mode 100644 index 0000000..dd18190 --- /dev/null +++ b/src/win/clear.cc @@ -0,0 +1,30 @@ +/* ttyutil - win/clear.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_clear) { + NanScope(); + // TODO(@bbuecherl) + NanReturnThis(); +} diff --git a/src/win/emit.cc b/src/win/emit.cc new file mode 100644 index 0000000..46a7973 --- /dev/null +++ b/src/win/emit.cc @@ -0,0 +1,106 @@ +/* ttyutil - win/emit.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_emit) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + if (obj->running) { + int ev = args[0]->Int32Value(); + INPUT_RECORD in[1]; + DWORD w; + + in[0].EventType = 0; + + switch (ev) { + case EVENT_KEY: + KEY_EVENT_RECORD kev; + + kev.bKeyDown = TRUE; + kev.wVirtualKeyCode = (WORD)args[1]->Int32Value(); + kev.dwControlKeyState = ttyu_win_state(args[2]->Int32Value()); + kev.uChar.UnicodeChar = static_cast(kev.wVirtualKeyCode); + kev.uChar.AsciiChar = static_cast(kev.wVirtualKeyCode); + kev.wRepeatCount = 1; + kev.wVirtualScanCode = MapVirtualKey(kev.wVirtualKeyCode, + MAPVK_VK_TO_VSC); + + in[0].EventType = KEY_EVENT; + in[0].Event.KeyEvent = kev; + break; + case EVENT_RESIZE: + WINDOW_BUFFER_SIZE_RECORD wev; + COORD size; + + size.X = args[1]->Int32Value(); + size.Y = args[2]->Int32Value(); + + wev.dwSize = size; + in[0].EventType = WINDOW_BUFFER_SIZE_EVENT; + in[0].Event.WindowBufferSizeEvent = wev; + break; + case EVENT_MOUSEDOWN: + case EVENT_MOUSEUP: + case EVENT_MOUSEMOVE: + case EVENT_MOUSEWHEEL: + case EVENT_MOUSEHWHEEL: + MOUSE_EVENT_RECORD mev; + COORD pos; + + in[0].EventType = MOUSE_EVENT; + pos.X = static_cast(args[2]->Int32Value()); + pos.Y = static_cast(args[3]->Int32Value() + obj->top); + mev.dwControlKeyState = ttyu_win_state(args[4]->Int32Value()); + + if (ev == EVENT_MOUSEUP) { + mev.dwButtonState = args[1]->Int32Value(); + mev.dwEventFlags = 0; + } else if (ev == EVENT_MOUSEDOWN) { + mev.dwButtonState = args[1]->Int32Value(); + mev.dwEventFlags = 2; + } else if (ev == EVENT_MOUSEMOVE) { + mev.dwEventFlags = 1; + } else if (ev == EVENT_MOUSEWHEEL) { + mev.dwEventFlags = 4; + } else if (ev == EVENT_MOUSEHWHEEL) { + mev.dwEventFlags = 8; + } else { + // invalidate event + in[0].EventType = 0; + } + + mev.dwMousePosition = pos; + in[0].Event.MouseEvent = mev; + break; + default: // EVENT_ERROR, EVENT_SIGNAL + // do nothing + break; + } + + if (in[0].EventType != 0) { + WriteConsoleInput(obj->hin, in, 1, &w); + } + } + NanReturnThis(); +} diff --git a/src/win/goto.cc b/src/win/goto.cc new file mode 100644 index 0000000..117d0d8 --- /dev/null +++ b/src/win/goto.cc @@ -0,0 +1,54 @@ +/* ttyutil - win/goto.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_setx) { + NanScope(); + // TODO(@bbuecherl) + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_getx) { + NanScope(); + // TODO(@bbuecherl) + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_sety) { + NanScope(); + // TODO(@bbuecherl) + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_gety) { + NanScope(); + // TODO(@bbuecherl) + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_goto) { + NanScope(); + // TODO(@bbuecherl) + NanReturnThis(); +} diff --git a/src/win/main.cc b/src/win/main.cc index 2d7760d..0905879 100644 --- a/src/win/main.cc +++ b/src/win/main.cc @@ -1,4 +1,4 @@ -/* ttyutil - win.cc - implements methods for windows systems (see include/win.h) +/* ttyutil - win/main.cc * https://github.com/clidejs/ttyutil * * Copyright Bernhard Bücherl @@ -32,384 +32,3 @@ ttyu_js_c::~ttyu_js_c() { stop = TRUE; ee_destroy(&emitter); } - -NAN_METHOD(ttyu_js_c::js_start) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - obj->running = TRUE; - obj->stop = FALSE; - - DBG("::js_start()"); - uv_mutex_init(&obj->emitlock); - uv_barrier_init(&obj->barrier, 2); - - obj->hin = GetStdHandle(STD_INPUT_HANDLE); - obj->hout = GetStdHandle(STD_OUTPUT_HANDLE); - - if (INVALID_HANDLE_VALUE == obj->hin || INVALID_HANDLE_VALUE == obj->hout) { - NanThrowError("invalid std handles"); - } - - GetConsoleMode(obj->hin, &(obj->old_mode)); - DWORD new_mode = ((obj->old_mode | ENABLE_MOUSE_INPUT | - ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT | ENABLE_WINDOW_INPUT) & - ~(ENABLE_QUICK_EDIT_MODE)); - SetConsoleMode(obj->hin, new_mode); - - DBG(" async queue start"); - NanAsyncQueueWorker(&obj->worker); - - DBG(" wait barrier"); - uv_barrier_wait(&obj->barrier); - DBG(" destroy barrier"); - uv_barrier_destroy(&obj->barrier); - DBG(" destroyed barrier"); - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::js_stop) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - obj->running = FALSE; - obj->stop = TRUE; - - SetConsoleMode(obj->hin, obj->old_mode); - - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::js_on) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - uv_mutex_lock(&obj->emitlock); - ee_on(&obj->emitter, args[0]->Int32Value(), - new NanCallback(v8::Local::Cast(args[1]))); - uv_mutex_unlock(&obj->emitlock); - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::js_off) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - uv_mutex_lock(&obj->emitlock); - ee_off(&obj->emitter, args[0]->Int32Value(), - new NanCallback(v8::Local::Cast(args[1]))); - uv_mutex_unlock(&obj->emitlock); - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::js_emit) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - if (obj->running) { - int ev = args[0]->Int32Value(); - INPUT_RECORD in[1]; - DWORD w; - - in[0].EventType = 0; - - switch (ev) { - case EVENT_KEY: - KEY_EVENT_RECORD kev; - - kev.bKeyDown = TRUE; - kev.wVirtualKeyCode = (WORD)args[1]->Int32Value(); - kev.dwControlKeyState = ttyu_win_state(args[2]->Int32Value()); - kev.uChar.UnicodeChar = static_cast(kev.wVirtualKeyCode); - kev.uChar.AsciiChar = static_cast(kev.wVirtualKeyCode); - kev.wRepeatCount = 1; - kev.wVirtualScanCode = MapVirtualKey(kev.wVirtualKeyCode, - MAPVK_VK_TO_VSC); - - in[0].EventType = KEY_EVENT; - in[0].Event.KeyEvent = kev; - break; - case EVENT_RESIZE: - WINDOW_BUFFER_SIZE_RECORD wev; - COORD size; - - size.X = args[1]->Int32Value(); - size.Y = args[2]->Int32Value(); - - wev.dwSize = size; - in[0].EventType = WINDOW_BUFFER_SIZE_EVENT; - in[0].Event.WindowBufferSizeEvent = wev; - break; - case EVENT_MOUSEDOWN: - case EVENT_MOUSEUP: - case EVENT_MOUSEMOVE: - case EVENT_MOUSEWHEEL: - case EVENT_MOUSEHWHEEL: - MOUSE_EVENT_RECORD mev; - COORD pos; - - in[0].EventType = MOUSE_EVENT; - pos.X = static_cast(args[2]->Int32Value()); - pos.Y = static_cast(args[3]->Int32Value() + obj->top); - mev.dwControlKeyState = ttyu_win_state(args[4]->Int32Value()); - - if (ev == EVENT_MOUSEUP) { - mev.dwButtonState = args[1]->Int32Value(); - mev.dwEventFlags = 0; - } else if (ev == EVENT_MOUSEDOWN) { - mev.dwButtonState = args[1]->Int32Value(); - mev.dwEventFlags = 2; - } else if (ev == EVENT_MOUSEMOVE) { - mev.dwEventFlags = 1; - } else if (ev == EVENT_MOUSEWHEEL) { - mev.dwEventFlags = 4; - } else if (ev == EVENT_MOUSEHWHEEL) { - mev.dwEventFlags = 8; - } else { - // invalidate event - in[0].EventType = 0; - } - - mev.dwMousePosition = pos; - in[0].Event.MouseEvent = mev; - break; - default: // EVENT_ERROR, EVENT_SIGNAL - // do nothing - break; - } - - if (in[0].EventType != 0) { - WriteConsoleInput(obj->hin, in, 1, &w); - } - } - NanReturnThis(); -} - -NAN_METHOD(ttyu_js_c::js_write) { - NanScope(); - printf("%s", TTYU_TOSTRING(args[0])); - NanReturnThis(); -} - - -bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, - ttyu_js_c *obj) { - DBG("::execute()", 2); - DWORD readed; - INPUT_RECORD ir[WIN_BUFFER_SIZE]; - DWORD i; - DBG(" start", 2); - if (obj->err) { - ttyu_event_t *event = - reinterpret_cast(malloc(sizeof(ttyu_event_t))); - ttyu_event_create_error(event); - progress.send(const_cast(event)); - if (obj->err) { - DBG(" killed", 2); - return FALSE; - } - obj->err->msg = NULL; - } - - DBG(" read input", 2); - - ReadConsoleInput(obj->hin, ir, WIN_BUFFER_SIZE, &readed); - if (obj->stop) { DBG(" exited", 2); return FALSE; } // exit - - for (i = 0; i < readed; ++i) { - if (MOUSE_EVENT == ir[i].EventType) { - ttyu_event_t *event = - reinterpret_cast(malloc(sizeof(ttyu_event_t))); - ttyu_event_create_mouse(event, EVENT_ERROR, - static_cast(ir[i].Event.MouseEvent.dwButtonState), - static_cast(ir[i].Event.MouseEvent.dwMousePosition.X), - static_cast(ir[i].Event.MouseEvent.dwMousePosition.Y - obj->top), - ttyu_win_ctrl(ir[i].Event.MouseEvent.dwControlKeyState)); - - if (ir[i].Event.MouseEvent.dwButtonState == 0 && - ir[i].Event.MouseEvent.dwEventFlags == 0) { - event->type = EVENT_MOUSEUP; - } else if (ir[i].Event.MouseEvent.dwEventFlags == 0 || - ir[i].Event.MouseEvent.dwEventFlags == 2) { - event->type = EVENT_MOUSEDOWN; - } else if (ir[i].Event.MouseEvent.dwEventFlags == 1) { - event->type = EVENT_MOUSEMOVE; - } else if (ir[i].Event.MouseEvent.dwEventFlags == 4) { - event->type = EVENT_MOUSEWHEEL; - } else if (ir[i].Event.MouseEvent.dwEventFlags == 8) { - event->type = EVENT_MOUSEHWHEEL; - } - - progress.send(const_cast(event)); - } else if (KEY_EVENT == ir[i].EventType && ir[i].Event.KeyEvent.bKeyDown) { - ttyu_event_t *event = - reinterpret_cast(malloc(sizeof(ttyu_event_t))); - char *ch = reinterpret_cast(malloc(sizeof(char) * 3)); - memcpy(ch, &(ir[i].Event.KeyEvent.uChar.UnicodeChar), sizeof(char) * 2); - ch[2] = '\0'; - - ttyu_event_create_key(event, ttyu_win_ctrl( - ir[i].Event.KeyEvent.dwControlKeyState), ch, - static_cast(ir[i].Event.KeyEvent.wVirtualKeyCode), - ttyu_win_which(ir[i].Event.KeyEvent.wVirtualKeyCode)); - - free(ch); - - progress.send(const_cast(event)); - } else if (WINDOW_BUFFER_SIZE_EVENT == ir[i].EventType) { - ttyu_event_t *event = - reinterpret_cast(malloc(sizeof(ttyu_event_t))); - - if (!ttyu_win_scr_update(obj, FALSE)) { - ttyu_event_create_error(event); - } else { - ttyu_event_create_resize(event); - } - progress.send(const_cast(event)); - } - } - DBG(" end", 2); - return TRUE; -} - -void ttyu_worker_c::handle(ttyu_event_t *event) { - DBG("::handle()", 1); - if (ee_count(&obj_->emitter, event->type) == 0 || obj_->stop || - !obj_->running) { - return; - } - - v8::Local obj = NanNew(); - switch (event->type) { - case EVENT_RESIZE: - obj->Set(NanNew("type"), EVENTSTRING_RESIZE); - break; - case EVENT_KEY: - obj->Set(NanNew("type"), EVENTSTRING_KEY); - obj->Set(NanNew("ctrl"), - NanNew(event->key->ctrl)); - obj->Set(NanNew("char"), NanNew(event->key->c)); - obj->Set(NanNew("code"), - NanNew(event->key->code)); - obj->Set(NanNew("which"), - NanNew(event->key->which)); - break; - case EVENT_MOUSEDOWN: - case EVENT_MOUSEUP: - case EVENT_MOUSEMOVE: - case EVENT_MOUSEWHEEL: - case EVENT_MOUSEHWHEEL: - if (event->type == EVENT_MOUSEDOWN) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEDOWN); - } else if (event->type == EVENT_MOUSEUP) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEUP); - } else if (event->type == EVENT_MOUSEMOVE) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEMOVE); - } else if (event->type == EVENT_MOUSEWHEEL) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEWHEEL); - } else if (event->type == EVENT_MOUSEHWHEEL) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEHWHEEL); - } - obj->Set(NanNew("button"), - NanNew(event->mouse->button)); - obj->Set(NanNew("x"), NanNew(event->mouse->x)); - obj->Set(NanNew("y"), NanNew(event->mouse->y)); - obj->Set(NanNew("ctrl"), - NanNew(event->mouse->ctrl)); - break; - default: // EVENT_ERROR, EVENT_SIGNAL - obj->Set(NanNew("type"), EVENTSTRING_ERROR); - obj->Set(NanNew("error"), NanError("TODO")); - event->type = EVENT_ERROR; - break; - } - uv_mutex_lock(&obj_->emitlock); - ee_emit(&obj_->emitter, event->type, obj); - uv_mutex_unlock(&obj_->emitlock); -} - -void ttyu_worker_c::Execute() { - DBG("::Execute()", 1); - ttyu_progress_c progress(this); - DBG(" barrier wait", 1); - uv_barrier_wait(&obj_->barrier); - DBG(" start execute loop", 1); - // loop execute until it returns false (error) - while (execute(progress, obj_)) continue; -} - -bool ttyu_win_scr_update(ttyu_js_c *obj, bool initial) { - CONSOLE_SCREEN_BUFFER_INFO con_info; - - if (!GetConsoleScreenBufferInfo(obj->hout, &con_info)) { - /*data->err->msg = ERRMSG(0x02); - return !(data->err->kill = TRUE);*/ - return FALSE; - } - - obj->top = con_info.srWindow.Top; - obj->width = con_info.dwSize.X; - obj->height = con_info.dwSize.Y - obj->top; - - obj->curx = con_info.dwCursorPosition.X; - obj->cury = con_info.dwCursorPosition.Y - obj->top; - - /*if(initial) { - data->base_color = (short)con_info.wAttributes; - } */ - return TRUE; -} - -int ttyu_win_ctrl(DWORD state) { - int ctrl = CTRL_NULL; - if (state & RIGHT_ALT_PRESSED || state & LEFT_ALT_PRESSED) { - ctrl |= CTRL_ALT; - } - if (state & RIGHT_CTRL_PRESSED || state & LEFT_CTRL_PRESSED) { - ctrl |= CTRL_CTRL; - } - if (state & SHIFT_PRESSED) { - ctrl |= CTRL_SHIFT; - } - if (state & ENHANCED_KEY) { - ctrl |= CTRL_ENHANCED; - } - if (state & NUMLOCK_ON) { - ctrl |= CTRL_NUMLOCK; - } - if (state & SCROLLLOCK_ON) { - ctrl |= CTRL_SCROLLLOCK; - } - if (state & CAPSLOCK_ON) { - ctrl |= CTRL_CAPSLOCK; - } - return ctrl; -} - -int ttyu_win_which(DWORD code) { - if (code > 0) { - return static_cast(code); - } - return WHICH_UNKNOWN; -} - -DWORD ttyu_win_state(int ctrl) { - DWORD state = 0; - if (ctrl & CTRL_ALT) { - state |= RIGHT_ALT_PRESSED & LEFT_ALT_PRESSED; - } - if (ctrl & CTRL_CTRL) { - state |= RIGHT_CTRL_PRESSED & LEFT_CTRL_PRESSED; - } - if (ctrl & CTRL_SHIFT) { - state |= SHIFT_PRESSED; - } - if (ctrl & CTRL_ENHANCED) { - state |= ENHANCED_KEY; - } - if (ctrl & CTRL_NUMLOCK) { - state |= NUMLOCK_ON; - } - if (ctrl & CTRL_SCROLLLOCK) { - state |= SCROLLLOCK_ON; - } - if (ctrl & CTRL_CAPSLOCK) { - state |= CAPSLOCK_ON; - } - return state; -} diff --git a/src/win/mode.cc b/src/win/mode.cc new file mode 100644 index 0000000..c42889f --- /dev/null +++ b/src/win/mode.cc @@ -0,0 +1,29 @@ +/* ttyutil - win/mode.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_mode) { + NanScope(); + NanReturnValue(NanNew(MODE_CMD)); +} diff --git a/src/win/off.cc b/src/win/off.cc new file mode 100644 index 0000000..8c65cec --- /dev/null +++ b/src/win/off.cc @@ -0,0 +1,34 @@ +/* ttyutil - win/off.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_off) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + uv_mutex_lock(&obj->emitlock); + ee_off(&obj->emitter, args[0]->Int32Value(), + new NanCallback(v8::Local::Cast(args[1]))); + uv_mutex_unlock(&obj->emitlock); + NanReturnThis(); +} diff --git a/src/win/on.cc b/src/win/on.cc new file mode 100644 index 0000000..9de2518 --- /dev/null +++ b/src/win/on.cc @@ -0,0 +1,34 @@ +/* ttyutil - win/on.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_on) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + uv_mutex_lock(&obj->emitlock); + ee_on(&obj->emitter, args[0]->Int32Value(), + new NanCallback(v8::Local::Cast(args[1]))); + uv_mutex_unlock(&obj->emitlock); + NanReturnThis(); +} diff --git a/src/win/resize.cc b/src/win/resize.cc new file mode 100644 index 0000000..8e465ae --- /dev/null +++ b/src/win/resize.cc @@ -0,0 +1,54 @@ +/* ttyutil - win/resize.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_getwidth) { + NanScope(); + // TODO(@bbuecherl) + NanReturnValue(NanNew(0)); +} + +NAN_METHOD(ttyu_js_c::js_getheight) { + NanScope(); + // TODO(@bbuecherl) + NanReturnValue(NanNew(0)); +} + +NAN_METHOD(ttyu_js_c::js_setwidth) { + NanScope(); + // TODO(@bbuecherl) + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_setheight) { + NanScope(); + // TODO(@bbuecherl) + NanReturnUndefined(); +} + +NAN_METHOD(ttyu_js_c::js_resize) { + NanScope(); + // TODO(@bbuecherl) + NanReturnThis(); +} diff --git a/src/win/start.cc b/src/win/start.cc new file mode 100644 index 0000000..b575a0c --- /dev/null +++ b/src/win/start.cc @@ -0,0 +1,58 @@ +/* ttyutil - win/start.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_start) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + obj->running = TRUE; + obj->stop = FALSE; + + DBG("::js_start()"); + uv_mutex_init(&obj->emitlock); + uv_barrier_init(&obj->barrier, 2); + + obj->hin = GetStdHandle(STD_INPUT_HANDLE); + obj->hout = GetStdHandle(STD_OUTPUT_HANDLE); + + if (INVALID_HANDLE_VALUE == obj->hin || INVALID_HANDLE_VALUE == obj->hout) { + NanThrowError("invalid std handles"); + } + + GetConsoleMode(obj->hin, &(obj->old_mode)); + DWORD new_mode = ((obj->old_mode | ENABLE_MOUSE_INPUT | + ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT | ENABLE_WINDOW_INPUT) & + ~(ENABLE_QUICK_EDIT_MODE)); + SetConsoleMode(obj->hin, new_mode); + + DBG(" async queue start"); + NanAsyncQueueWorker(&obj->worker); + + DBG(" wait barrier"); + uv_barrier_wait(&obj->barrier); + DBG(" destroy barrier"); + uv_barrier_destroy(&obj->barrier); + DBG(" destroyed barrier"); + NanReturnThis(); +} diff --git a/src/win/stop.cc b/src/win/stop.cc new file mode 100644 index 0000000..c1a942a --- /dev/null +++ b/src/win/stop.cc @@ -0,0 +1,35 @@ +/* ttyutil - win/stop.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_stop) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + obj->running = FALSE; + obj->stop = TRUE; + + SetConsoleMode(obj->hin, obj->old_mode); + + NanReturnThis(); +} diff --git a/src/win/utils.cc b/src/win/utils.cc new file mode 100644 index 0000000..0187f72 --- /dev/null +++ b/src/win/utils.cc @@ -0,0 +1,105 @@ +/* ttyutil - win/utils.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +bool ttyu_win_scr_update(ttyu_js_c *obj, bool initial) { + CONSOLE_SCREEN_BUFFER_INFO con_info; + + if (!GetConsoleScreenBufferInfo(obj->hout, &con_info)) { + /*data->err->msg = ERRMSG(0x02); + return !(data->err->kill = TRUE);*/ + return FALSE; + } + + obj->top = con_info.srWindow.Top; + obj->width = con_info.dwSize.X; + obj->height = con_info.dwSize.Y - obj->top; + + obj->curx = con_info.dwCursorPosition.X; + obj->cury = con_info.dwCursorPosition.Y - obj->top; + + /*if(initial) { + data->base_color = (short)con_info.wAttributes; + } */ + return TRUE; +} + +int ttyu_win_ctrl(DWORD state) { + int ctrl = CTRL_NULL; + if (state & RIGHT_ALT_PRESSED || state & LEFT_ALT_PRESSED) { + ctrl |= CTRL_ALT; + } + if (state & RIGHT_CTRL_PRESSED || state & LEFT_CTRL_PRESSED) { + ctrl |= CTRL_CTRL; + } + if (state & SHIFT_PRESSED) { + ctrl |= CTRL_SHIFT; + } + if (state & ENHANCED_KEY) { + ctrl |= CTRL_ENHANCED; + } + if (state & NUMLOCK_ON) { + ctrl |= CTRL_NUMLOCK; + } + if (state & SCROLLLOCK_ON) { + ctrl |= CTRL_SCROLLLOCK; + } + if (state & CAPSLOCK_ON) { + ctrl |= CTRL_CAPSLOCK; + } + return ctrl; +} + +int ttyu_win_which(DWORD code) { + if (code > 0) { + return static_cast(code); + } + return WHICH_UNKNOWN; +} + +DWORD ttyu_win_state(int ctrl) { + DWORD state = 0; + if (ctrl & CTRL_ALT) { + state |= RIGHT_ALT_PRESSED & LEFT_ALT_PRESSED; + } + if (ctrl & CTRL_CTRL) { + state |= RIGHT_CTRL_PRESSED & LEFT_CTRL_PRESSED; + } + if (ctrl & CTRL_SHIFT) { + state |= SHIFT_PRESSED; + } + if (ctrl & CTRL_ENHANCED) { + state |= ENHANCED_KEY; + } + if (ctrl & CTRL_NUMLOCK) { + state |= NUMLOCK_ON; + } + if (ctrl & CTRL_SCROLLLOCK) { + state |= SCROLLLOCK_ON; + } + if (ctrl & CTRL_CAPSLOCK) { + state |= CAPSLOCK_ON; + } + return state; +} diff --git a/src/win/worker.cc b/src/win/worker.cc new file mode 100644 index 0000000..6c06f52 --- /dev/null +++ b/src/win/worker.cc @@ -0,0 +1,170 @@ +/* ttyutil - win/worker.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, + ttyu_js_c *obj) { + DBG("::execute()"); + DWORD readed; + INPUT_RECORD ir[WIN_BUFFER_SIZE]; + DWORD i; + DBG(" start"); + if (obj->err) { + ttyu_event_t *event = + reinterpret_cast(malloc(sizeof(ttyu_event_t))); + ttyu_event_create_error(event); + progress.send(const_cast(event)); + if (obj->err) { + DBG(" killed"); + return FALSE; + } + obj->err->msg = NULL; + } + + DBG(" read input"); + + ReadConsoleInput(obj->hin, ir, WIN_BUFFER_SIZE, &readed); + if (obj->stop) { DBG(" exited"); return FALSE; } // exit + + for (i = 0; i < readed; ++i) { + if (MOUSE_EVENT == ir[i].EventType) { + ttyu_event_t *event = + reinterpret_cast(malloc(sizeof(ttyu_event_t))); + ttyu_event_create_mouse(event, EVENT_ERROR, + static_cast(ir[i].Event.MouseEvent.dwButtonState), + static_cast(ir[i].Event.MouseEvent.dwMousePosition.X), + static_cast(ir[i].Event.MouseEvent.dwMousePosition.Y - obj->top), + ttyu_win_ctrl(ir[i].Event.MouseEvent.dwControlKeyState)); + + if (ir[i].Event.MouseEvent.dwButtonState == 0 && + ir[i].Event.MouseEvent.dwEventFlags == 0) { + event->type = EVENT_MOUSEUP; + } else if (ir[i].Event.MouseEvent.dwEventFlags == 0 || + ir[i].Event.MouseEvent.dwEventFlags == 2) { + event->type = EVENT_MOUSEDOWN; + } else if (ir[i].Event.MouseEvent.dwEventFlags == 1) { + event->type = EVENT_MOUSEMOVE; + } else if (ir[i].Event.MouseEvent.dwEventFlags == 4) { + event->type = EVENT_MOUSEWHEEL; + } else if (ir[i].Event.MouseEvent.dwEventFlags == 8) { + event->type = EVENT_MOUSEHWHEEL; + } + + progress.send(const_cast(event)); + } else if (KEY_EVENT == ir[i].EventType && ir[i].Event.KeyEvent.bKeyDown) { + ttyu_event_t *event = + reinterpret_cast(malloc(sizeof(ttyu_event_t))); + char *ch = reinterpret_cast(malloc(sizeof(char) * 3)); + memcpy(ch, &(ir[i].Event.KeyEvent.uChar.UnicodeChar), sizeof(char) * 2); + ch[2] = '\0'; + + ttyu_event_create_key(event, ttyu_win_ctrl( + ir[i].Event.KeyEvent.dwControlKeyState), ch, + static_cast(ir[i].Event.KeyEvent.wVirtualKeyCode), + ttyu_win_which(ir[i].Event.KeyEvent.wVirtualKeyCode)); + + free(ch); + + progress.send(const_cast(event)); + } else if (WINDOW_BUFFER_SIZE_EVENT == ir[i].EventType) { + ttyu_event_t *event = + reinterpret_cast(malloc(sizeof(ttyu_event_t))); + + if (!ttyu_win_scr_update(obj, FALSE)) { + ttyu_event_create_error(event); + } else { + ttyu_event_create_resize(event); + } + progress.send(const_cast(event)); + } + } + DBG(" end"); + return TRUE; +} + +void ttyu_worker_c::handle(ttyu_event_t *event) { + DBG("::handle()"); + if (ee_count(&obj_->emitter, event->type) == 0 || obj_->stop || + !obj_->running) { + return; + } + + v8::Local obj = NanNew(); + switch (event->type) { + case EVENT_RESIZE: + obj->Set(NanNew("type"), EVENTSTRING_RESIZE); + break; + case EVENT_KEY: + obj->Set(NanNew("type"), EVENTSTRING_KEY); + obj->Set(NanNew("ctrl"), + NanNew(event->key->ctrl)); + obj->Set(NanNew("char"), NanNew(event->key->c)); + obj->Set(NanNew("code"), + NanNew(event->key->code)); + obj->Set(NanNew("which"), + NanNew(event->key->which)); + break; + case EVENT_MOUSEDOWN: + case EVENT_MOUSEUP: + case EVENT_MOUSEMOVE: + case EVENT_MOUSEWHEEL: + case EVENT_MOUSEHWHEEL: + if (event->type == EVENT_MOUSEDOWN) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEDOWN); + } else if (event->type == EVENT_MOUSEUP) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEUP); + } else if (event->type == EVENT_MOUSEMOVE) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEMOVE); + } else if (event->type == EVENT_MOUSEWHEEL) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEWHEEL); + } else if (event->type == EVENT_MOUSEHWHEEL) { + obj->Set(NanNew("type"), EVENTSTRING_MOUSEHWHEEL); + } + obj->Set(NanNew("button"), + NanNew(event->mouse->button)); + obj->Set(NanNew("x"), NanNew(event->mouse->x)); + obj->Set(NanNew("y"), NanNew(event->mouse->y)); + obj->Set(NanNew("ctrl"), + NanNew(event->mouse->ctrl)); + break; + default: // EVENT_ERROR, EVENT_SIGNAL + obj->Set(NanNew("type"), EVENTSTRING_ERROR); + obj->Set(NanNew("error"), NanError("TODO")); + event->type = EVENT_ERROR; + break; + } + uv_mutex_lock(&obj_->emitlock); + ee_emit(&obj_->emitter, event->type, obj); + uv_mutex_unlock(&obj_->emitlock); +} + +void ttyu_worker_c::Execute() { + DBG("::Execute()"); + ttyu_progress_c progress(this); + DBG(" barrier wait"); + uv_barrier_wait(&obj_->barrier); + DBG(" start execute loop"); + // loop execute until it returns false (error) + while (execute(progress, obj_)) continue; +} diff --git a/src/win/write.cc b/src/win/write.cc new file mode 100644 index 0000000..cb200d3 --- /dev/null +++ b/src/win/write.cc @@ -0,0 +1,30 @@ +/* ttyutil - win/write.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_write) { + NanScope(); + printf("%s", TTYU_TOSTRING(args[0])); + NanReturnThis(); +} From 1846d108477e9d5fa26fad1ac5d328953935772c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Wed, 10 Jun 2015 23:04:54 +0200 Subject: [PATCH 17/28] added errors --- include/ttyu.h | 4 ++++ include/win.h | 4 +--- src/unix/beep.cc | 1 + src/unix/clear.cc | 1 + src/unix/emit.cc | 1 + src/unix/goto.cc | 10 ++++++++++ src/unix/mode.cc | 1 + src/unix/stop.cc | 1 + src/win/beep.cc | 2 ++ src/win/clear.cc | 2 ++ src/win/emit.cc | 2 ++ src/win/goto.cc | 10 ++++++++++ src/win/stop.cc | 1 + 13 files changed, 37 insertions(+), 3 deletions(-) diff --git a/include/ttyu.h b/include/ttyu.h index 4113069..a83adf5 100644 --- a/include/ttyu.h +++ b/include/ttyu.h @@ -77,6 +77,10 @@ TTYU_INLINE ttyu_error_t _ERRMSG(int id) { } #define ERRMSG(id) &_ERRMSG(id) +#define THROW_IF_STOPPED(obj) if (!obj->running) { \ + return NanThrowError("Function requires ttyu to be running"); \ +} + // callback call function for the event emitter int ttyu_ee_cb_call(ee__listener_t *l, EE_DATA_ARG(data)); // callback compare function for the event emitter diff --git a/include/win.h b/include/win.h index 04b7db5..f3dbfe9 100644 --- a/include/win.h +++ b/include/win.h @@ -86,9 +86,7 @@ class ttyu_worker_c : public NanAsyncWorker { void Execute(); - void WorkComplete() { - // do nothing - } + void WorkComplete() { /* do nothing */ } private: void send_(const ttyu_event_t *event) { diff --git a/src/unix/beep.cc b/src/unix/beep.cc index 3f3bb2b..b6601c9 100644 --- a/src/unix/beep.cc +++ b/src/unix/beep.cc @@ -25,6 +25,7 @@ NAN_METHOD(ttyu_js_c::js_beep) { NanScope(); + THROW_IF_STOPPED(ObjectWrap::Unwrap(args.This())); beep(); NanReturnThis(); } diff --git a/src/unix/clear.cc b/src/unix/clear.cc index 547fd86..f4a335f 100644 --- a/src/unix/clear.cc +++ b/src/unix/clear.cc @@ -26,6 +26,7 @@ NAN_METHOD(ttyu_js_c::js_clear) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); werase(obj->win); NanReturnThis(); } diff --git a/src/unix/emit.cc b/src/unix/emit.cc index 2341cf0..a27d157 100644 --- a/src/unix/emit.cc +++ b/src/unix/emit.cc @@ -32,6 +32,7 @@ NAN_METHOD(ttyu_js_c::js_emit) { int arg3 = args[3]->Int32Value(); int arg4 = args[4]->Int32Value(); ttyu_event_t event; + THROW_IF_STOPPED(obj); switch (arg0) { case EVENT_KEY: { int c = -1; diff --git a/src/unix/goto.cc b/src/unix/goto.cc index c543222..3f98696 100644 --- a/src/unix/goto.cc +++ b/src/unix/goto.cc @@ -25,30 +25,40 @@ NAN_METHOD(ttyu_js_c::js_setx) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); // TODO(@bbuecherl) NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_getx) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); // TODO(@bbuecherl) NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_sety) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); // TODO(@bbuecherl) NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_gety) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); // TODO(@bbuecherl) NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_goto) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); // TODO(@bbuecherl) NanReturnThis(); } diff --git a/src/unix/mode.cc b/src/unix/mode.cc index 0c77c10..7e3924d 100644 --- a/src/unix/mode.cc +++ b/src/unix/mode.cc @@ -26,5 +26,6 @@ NAN_METHOD(ttyu_js_c::js_mode) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); NanReturnValue(NanNew(obj->mode)); } diff --git a/src/unix/stop.cc b/src/unix/stop.cc index c648c8d..8e80a15 100644 --- a/src/unix/stop.cc +++ b/src/unix/stop.cc @@ -26,6 +26,7 @@ NAN_METHOD(ttyu_js_c::js_stop) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); obj->running = FALSE; obj->stop = TRUE; diff --git a/src/win/beep.cc b/src/win/beep.cc index a35d88a..83ed6db 100644 --- a/src/win/beep.cc +++ b/src/win/beep.cc @@ -25,6 +25,8 @@ NAN_METHOD(ttyu_js_c::js_beep) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); // TODO(@bbuecherl) NanReturnThis(); } diff --git a/src/win/clear.cc b/src/win/clear.cc index dd18190..81c471f 100644 --- a/src/win/clear.cc +++ b/src/win/clear.cc @@ -25,6 +25,8 @@ NAN_METHOD(ttyu_js_c::js_clear) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); // TODO(@bbuecherl) NanReturnThis(); } diff --git a/src/win/emit.cc b/src/win/emit.cc index 46a7973..c947a5c 100644 --- a/src/win/emit.cc +++ b/src/win/emit.cc @@ -26,6 +26,8 @@ NAN_METHOD(ttyu_js_c::js_emit) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); if (obj->running) { int ev = args[0]->Int32Value(); INPUT_RECORD in[1]; diff --git a/src/win/goto.cc b/src/win/goto.cc index 117d0d8..482f8f2 100644 --- a/src/win/goto.cc +++ b/src/win/goto.cc @@ -25,30 +25,40 @@ NAN_METHOD(ttyu_js_c::js_setx) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); // TODO(@bbuecherl) NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_getx) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); // TODO(@bbuecherl) NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_sety) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); // TODO(@bbuecherl) NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_gety) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); // TODO(@bbuecherl) NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_goto) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); // TODO(@bbuecherl) NanReturnThis(); } diff --git a/src/win/stop.cc b/src/win/stop.cc index c1a942a..ac38068 100644 --- a/src/win/stop.cc +++ b/src/win/stop.cc @@ -26,6 +26,7 @@ NAN_METHOD(ttyu_js_c::js_stop) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); obj->running = FALSE; obj->stop = TRUE; From 160877a84ff7057cc122c41849fb2422dd050839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Thu, 11 Jun 2015 01:11:08 +0200 Subject: [PATCH 18/28] fix build error on variadic macros --- .travis.yml | 2 +- include/cdebug.h | 2 +- src/core/utilities.cc | 2 +- src/unix/mode.cc | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index a2086f1..02c9971 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ node_js: - "0.12" - "iojs-v2.2.0" install: - - npm install + - npm install --verbose - curl -G -v http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py -o cpplint.py script: - npm run-script lint diff --git a/include/cdebug.h b/include/cdebug.h index bda3d3f..c2d5527 100644 --- a/include/cdebug.h +++ b/include/cdebug.h @@ -40,7 +40,7 @@ # endif // CDEBUG_FILE #else // ifndef CDEBUG #define DBG(msg) -#define SDBG(f, msg) +#define SDBG(f, ...) #endif // CDEBUG diff --git a/src/core/utilities.cc b/src/core/utilities.cc index b2325e2..8a070a5 100644 --- a/src/core/utilities.cc +++ b/src/core/utilities.cc @@ -106,7 +106,7 @@ TTYU_INLINE int16_t util_rgb2term(const char *rgb) { int16_t cur = 0; int16_t pos = 0; - for (uint8_t i = static_cast(strlen(rgb)); i >= 0; --i) { + for (uint8_t i = static_cast(strlen(rgb)); i; --i) { if (rgb[i] == ',') { ++cur; pos = 0; diff --git a/src/unix/mode.cc b/src/unix/mode.cc index 7e3924d..0c77c10 100644 --- a/src/unix/mode.cc +++ b/src/unix/mode.cc @@ -26,6 +26,5 @@ NAN_METHOD(ttyu_js_c::js_mode) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); NanReturnValue(NanNew(obj->mode)); } From 2c5ad9e97e13a9c8e3a4394d6da86e143daa54c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Sat, 13 Jun 2015 01:38:52 +0200 Subject: [PATCH 19/28] added errors, improved mutexes, implemented more unixy functionality --- include/unix.h | 3 +++ include/utils.h | 6 ++++++ package.json | 9 ++++----- src/unix/clear.cc | 18 +++++++++++++++++- src/unix/curses.cc | 6 ++---- src/unix/emit.cc | 6 ++---- src/unix/goto.cc | 17 ++++++++++------- src/unix/main.cc | 3 ++- src/unix/off.cc | 6 ++---- src/unix/on.cc | 6 ++---- src/unix/resize.cc | 9 +++++++++ src/unix/start.cc | 2 ++ src/unix/worker.cc | 20 +++++++++++--------- tests/key.js | 34 ++++++++++------------------------ 14 files changed, 82 insertions(+), 63 deletions(-) diff --git a/include/unix.h b/include/unix.h index 329ee2c..5cca323 100644 --- a/include/unix.h +++ b/include/unix.h @@ -28,6 +28,7 @@ #define NCURSES_OPAQUE FALSE #include #include +#include #include #include @@ -127,6 +128,8 @@ class ttyu_worker_c : public NanAsyncWorker { uv_mutex_t ungetlock; \ uv_cond_t condition; \ int mode; \ + int x; \ + int y; \ bool worker_run; \ std::queue unget_stack; \ std::vector emit_stack diff --git a/include/utils.h b/include/utils.h index 90222a3..5f58f4e 100644 --- a/include/utils.h +++ b/include/utils.h @@ -36,6 +36,12 @@ #define TTYU_TOSTRING(handle) \ (new v8::String::Utf8Value(handle->ToString()))->operator*() +#define MUTEX_LOCK(mutex, action) ({ \ + uv_mutex_lock(mutex); \ + action; \ + uv_mutex_unlock(mutex); \ +}) + #if defined(__GNUC__) && !(defined(DEBUG) && DEBUG) # define TTYU_INLINE inline __attribute__((always_inline)) #elif defined(_MSC_VER) && !(defined(DEBUG) && DEBUG) diff --git a/package.json b/package.json index 1354025..1ffebb5 100644 --- a/package.json +++ b/package.json @@ -29,12 +29,11 @@ "nan": "1.8.4" }, "devDependencies": { - "chai": "2.1.2", + "chai": "3.0.0", "it-each": "0.3.1", - "mocha": "2.2.1", - "node-gyp": "1.0.2", - "node-is": "0.5.2", - "pangyp": "2.1.0" + "mocha": "2.2.5", + "node-gyp": "2.0.1", + "node-is": "0.5.2" }, "engines": { "node": ">=0.8.0" diff --git a/src/unix/clear.cc b/src/unix/clear.cc index f4a335f..8be0865 100644 --- a/src/unix/clear.cc +++ b/src/unix/clear.cc @@ -27,6 +27,22 @@ NAN_METHOD(ttyu_js_c::js_clear) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); THROW_IF_STOPPED(obj); - werase(obj->win); + if (args.Length() == 4) { + int x = args[0]->Int32Value(); + int y = args[1]->Int32Value(); + int w = args[2]->Int32Value(); + int h = args[3]->Int32Value(); + wmove(obj->win, x, y); + for (int j = 0; j < h; ++j) { + for (int i = 0; i < w; ++i) { + std::cout << " "; + } + } + std::cout << "\r\n"; + } else { + werase(obj->win); + } + wmove(obj->win, obj->x, obj->y); + wrefresh(obj->win); NanReturnThis(); } diff --git a/src/unix/curses.cc b/src/unix/curses.cc index 8f86668..ae29492 100644 --- a/src/unix/curses.cc +++ b/src/unix/curses.cc @@ -194,12 +194,10 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { } if (event.type != EVENT_NONE) { - uv_mutex_lock(&obj->emitstacklock); - { + MUTEX_LOCK(&obj->emitstacklock, { obj->emit_stack.push_back(event); uv_cond_signal(&obj->condition); - } - uv_mutex_unlock(&obj->emitstacklock); + }); } return 0; } diff --git a/src/unix/emit.cc b/src/unix/emit.cc index a27d157..8468499 100644 --- a/src/unix/emit.cc +++ b/src/unix/emit.cc @@ -65,11 +65,9 @@ NAN_METHOD(ttyu_js_c::js_emit) { } if (event.type != EVENT_NONE) { - uv_mutex_lock(&obj->ungetlock); - { + MUTEX_LOCK(&obj->ungetlock, { obj->unget_stack.push(event); - } - uv_mutex_unlock(&obj->ungetlock); + }); } NanReturnThis(); } diff --git a/src/unix/goto.cc b/src/unix/goto.cc index 3f98696..5e00938 100644 --- a/src/unix/goto.cc +++ b/src/unix/goto.cc @@ -27,7 +27,7 @@ NAN_METHOD(ttyu_js_c::js_setx) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); THROW_IF_STOPPED(obj); - // TODO(@bbuecherl) + obj->x = args[0]->Int32Value(); NanReturnUndefined(); } @@ -35,15 +35,14 @@ NAN_METHOD(ttyu_js_c::js_getx) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); THROW_IF_STOPPED(obj); - // TODO(@bbuecherl) - NanReturnUndefined(); + NanReturnValue(NanNew(obj->x)); } NAN_METHOD(ttyu_js_c::js_sety) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); THROW_IF_STOPPED(obj); - // TODO(@bbuecherl) + obj->y = args[0]->Int32Value(); NanReturnUndefined(); } @@ -51,14 +50,18 @@ NAN_METHOD(ttyu_js_c::js_gety) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); THROW_IF_STOPPED(obj); - // TODO(@bbuecherl) - NanReturnUndefined(); + NanReturnValue(NanNew(obj->y)); } NAN_METHOD(ttyu_js_c::js_goto) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); THROW_IF_STOPPED(obj); - // TODO(@bbuecherl) + if(args.Length() == 2) { + obj->x = args[0]->Int32Value(); + obj->y = args[1]->Int32Value(); + wmove(obj->win, obj->x, obj->y); + wrefresh(obj->win); + } NanReturnThis(); } diff --git a/src/unix/main.cc b/src/unix/main.cc index bbdfe71..faa7922 100644 --- a/src/unix/main.cc +++ b/src/unix/main.cc @@ -23,7 +23,8 @@ */ #include -ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), mode(MODE_VT100) { +ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), mode(MODE_VT100), + x(0), y(0) { ee_init(&emitter, ttyu_ee_cb_call, ttyu_ee_compare); } diff --git a/src/unix/off.cc b/src/unix/off.cc index 2b5b4e1..756ec56 100644 --- a/src/unix/off.cc +++ b/src/unix/off.cc @@ -26,11 +26,9 @@ NAN_METHOD(ttyu_js_c::js_off) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - uv_mutex_lock(&obj->emitlock); - { + MUTEX_LOCK(&obj->emitlock, { ee_off(&obj->emitter, args[0]->Int32Value(), new NanCallback(v8::Local::Cast(args[1]))); - } - uv_mutex_unlock(&obj->emitlock); + }); NanReturnThis(); } diff --git a/src/unix/on.cc b/src/unix/on.cc index 68b8c84..08b8194 100644 --- a/src/unix/on.cc +++ b/src/unix/on.cc @@ -26,11 +26,9 @@ NAN_METHOD(ttyu_js_c::js_on) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - uv_mutex_lock(&obj->emitlock); - { + MUTEX_LOCK(&obj->emitlock, { ee_on(&obj->emitter, args[0]->Int32Value(), new NanCallback(v8::Local::Cast(args[1]))); - } - uv_mutex_unlock(&obj->emitlock); + }); NanReturnThis(); } diff --git a/src/unix/resize.cc b/src/unix/resize.cc index 9f0e4d7..13ea4f5 100644 --- a/src/unix/resize.cc +++ b/src/unix/resize.cc @@ -39,22 +39,31 @@ NAN_METHOD(ttyu_js_c::js_getheight) { NAN_METHOD(ttyu_js_c::js_setwidth) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); resizeterm(args[0]->Int32Value(), w.ws_row); + wrefresh(obj->win); NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_setheight) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); resizeterm(w.ws_col, args[0]->Int32Value()); + wrefresh(obj->win); NanReturnUndefined(); } NAN_METHOD(ttyu_js_c::js_resize) { NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); resizeterm(args[0]->Int32Value(), args[1]->Int32Value()); + wrefresh(obj->win); NanReturnThis(); } diff --git a/src/unix/start.cc b/src/unix/start.cc index f222419..8276003 100644 --- a/src/unix/start.cc +++ b/src/unix/start.cc @@ -30,6 +30,8 @@ NAN_METHOD(ttyu_js_c::js_start) { obj->stop = FALSE; obj->worker_run = TRUE; obj->win = initscr(); + obj->x = getcurx(obj->win); + obj->y = getcury(obj->win); uv_barrier_init(&obj->barrier, 3); uv_mutex_init(&obj->emitlock); diff --git a/src/unix/worker.cc b/src/unix/worker.cc index 46766f5..23809b4 100644 --- a/src/unix/worker.cc +++ b/src/unix/worker.cc @@ -30,8 +30,7 @@ void ttyu_js_c::check_queue() { } void ttyu_worker_c::Execute() { - uv_mutex_lock(&obj->emitstacklock); - { + MUTEX_LOCK(&obj->emitstacklock,{ if (obj->worker_run) { obj->worker_run = FALSE; uv_barrier_wait(&obj->barrier); @@ -47,8 +46,7 @@ void ttyu_worker_c::Execute() { std::copy(obj->emit_stack.begin(), obj->emit_stack.end(), std::back_inserter(emit_stack)); obj->emit_stack.clear(); - } - uv_mutex_unlock(&obj->emitstacklock); + }); } void ttyu_worker_c::HandleOKCallback() { @@ -58,10 +56,12 @@ void ttyu_worker_c::HandleOKCallback() { ttyu_event_t event = emit_stack[i]; SDBG("::HandleOKCallback %d %d", i, event.type); - if (ee_count(&obj->emitter, event.type) == 0 || - event.type == EVENT_NONE) { - continue; // fast skip - } + MUTEX_LOCK(&obj->emitlock, { + if (ee_count(&obj->emitter, event.type) == 0 || + event.type == EVENT_NONE) { + continue; // fast skip + } + }); v8::Local jsobj = NanNew(); switch (event.type) { @@ -111,7 +111,9 @@ void ttyu_worker_c::HandleOKCallback() { break; } - ee_emit(&obj->emitter, event.type, jsobj); + MUTEX_LOCK(&obj->emitlock, { + ee_emit(&obj->emitter, event.type, jsobj); + }); } emit_stack.clear(); obj->check_queue(); diff --git a/tests/key.js b/tests/key.js index 6075d3e..c65f1f2 100644 --- a/tests/key.js +++ b/tests/key.js @@ -12,7 +12,7 @@ for(var i = 0; i < keys.length; ++i) { } } -var unix_required = [ +var unix_required = [/* Const.Which.BACK, Const.Which.TAB, Const.Which.CLEAR, @@ -30,7 +30,7 @@ var unix_required = [ Const.Which.PRINT, Const.Which.INSERT, Const.Which.DELETE, - Const.Which.HELP, + Const.Which.HELP,*/ Const.Which.CHAR0, Const.Which.CHAR1, Const.Which.CHAR2, @@ -66,7 +66,7 @@ var unix_required = [ Const.Which.CHARW, Const.Which.CHARX, Const.Which.CHARY, - Const.Which.CHARZ, + Const.Which.CHARZ/*, Const.Which.F1, Const.Which.F2, Const.Which.F3, @@ -91,11 +91,9 @@ var unix_required = [ Const.Which.F22, Const.Which.F23, Const.Which.F24, - Const.Which.BROWSER_REFRESH + Const.Which.BROWSER_REFRESH*/ ]; -var current = []; - module.exports = function(ttyu, expect) { describe("TTYUtil `key` event handling", function() { describe(".which", function() { @@ -103,23 +101,11 @@ module.exports = function(ttyu, expect) { ttyu.start(); }); - it.each(which, "should recognize character #%s", ['element'], - function(element, next) { + it.each(unix_required, "should recognize character #%s", + ['element'], function(element, next) { this.timeout(500); - if(!(process.platform !== "win32" && - unix_required.indexOf(element) === -1)) { - ttyu.on(ttyu.EVENT.KEY, createTest(element, next)); - ttyu.emit(ttyu.KeyEvent(element, 0)); - } else { - next(); - } - }); - - afterEach(function() { - var el; - while((el = current.pop())) { - ttyu.removeListener(ttyu.EVENT.KEY, el); - } + createTest(element, next); + ttyu.emit(ttyu.KeyEvent(element, 0)); }); after(function() { @@ -137,10 +123,10 @@ module.exports = function(ttyu, expect) { } else { expect(ev.which).to.be.equal(element); } + ttyu.off(ttyu.EVENT.KEY, test); callback(); }; - current.push(test); - + ttyu.on(ttyu.EVENT.KEY, test); return test; } }); From 1d3f7593a24a9fb9370d1371cfdcd83e77f3dfb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Mon, 15 Jun 2015 00:23:47 +0200 Subject: [PATCH 20/28] more work on unix --- .gitmodules | 3 --- binding.gyp | 6 ------ deps/ee.c | 1 - include/ttyu.h | 16 +--------------- include/unix.h | 9 ++++++++- lib/export.js | 11 +++++++---- src/core/ttyu.cc | 21 +-------------------- src/unix/main.cc | 6 ++---- src/unix/off.cc | 34 ---------------------------------- src/unix/on.cc | 34 ---------------------------------- src/unix/worker.cc | 15 ++++----------- src/win/emit.cc | 1 - src/win/main.cc | 5 +---- src/win/off.cc | 34 ---------------------------------- src/win/on.cc | 34 ---------------------------------- src/win/worker.cc | 9 +-------- 16 files changed, 25 insertions(+), 214 deletions(-) delete mode 160000 deps/ee.c delete mode 100644 src/unix/off.cc delete mode 100644 src/unix/on.cc delete mode 100644 src/win/off.cc delete mode 100644 src/win/on.cc diff --git a/.gitmodules b/.gitmodules index c6bcac9..30fdbce 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "deps/ee.c"] - path = deps/ee.c - url = git://github.com/clidejs/ee.c.git [submodule "deps/ncurses"] path = deps/ncurses url = git://ncurses.scripts.mit.edu/ncurses.git diff --git a/binding.gyp b/binding.gyp index a84bc13..65da137 100644 --- a/binding.gyp +++ b/binding.gyp @@ -4,11 +4,9 @@ "target_name": "ttyu", "include_dirs" : [ " #include -// predefine event data and callbacks for ee.c -#define EE_DATA_TYPE v8::Local -#define EE_DATA_ARG(name) v8::Local name -#define EE_CB_TYPE NanCallback * -#define EE_CB_ARG(name) NanCallback *name -#include // NOLINT - // define TRUE & FALSE #ifndef TRUE # define TRUE 1 @@ -81,11 +74,6 @@ TTYU_INLINE ttyu_error_t _ERRMSG(int id) { return NanThrowError("Function requires ttyu to be running"); \ } -// callback call function for the event emitter -int ttyu_ee_cb_call(ee__listener_t *l, EE_DATA_ARG(data)); -// callback compare function for the event emitter -int ttyu_ee_compare(EE_CB_ARG(cb1), EE_CB_ARG(cb2)); - // key event structure typedef struct ttyu_key_s { int ctrl; @@ -134,8 +122,6 @@ class ttyu_js_c : public node::ObjectWrap { static NAN_METHOD(js_new); static NAN_METHOD(js_start); static NAN_METHOD(js_stop); - static NAN_METHOD(js_on); - static NAN_METHOD(js_off); static NAN_METHOD(js_emit); static NAN_METHOD(js_running); static NAN_METHOD(js_getwidth); @@ -157,7 +143,7 @@ class ttyu_js_c : public node::ObjectWrap { ttyu_error_t *err; bool running; bool stop; - ee_emitter_t emitter; + NanCallback *emitter; PLATFORM_DEPENDENT_FIELDS; }; diff --git a/include/unix.h b/include/unix.h index 5cca323..88c3d6c 100644 --- a/include/unix.h +++ b/include/unix.h @@ -115,6 +115,12 @@ class ttyu_worker_c : public NanAsyncWorker { std::vector emit_stack; }; +typedef struct ttyu_listener_s { + int type; + NanCallback *cb; + bool on; +} ttyu_listener_t; + #define PLATFORM_DEPENDENT_FIELDS \ void check_queue(); \ static void curses_thread_func(void *that); \ @@ -132,6 +138,7 @@ class ttyu_worker_c : public NanAsyncWorker { int y; \ bool worker_run; \ std::queue unget_stack; \ - std::vector emit_stack + std::vector emit_stack; \ + std::vector listener_modifiers #endif // INCLUDE_UNIX_H_# diff --git a/lib/export.js b/lib/export.js index 6c56782..4bd634f 100644 --- a/lib/export.js +++ b/lib/export.js @@ -1,3 +1,4 @@ +var events = require("events"); var Const = require("./const"); var signal = require("./signal"); var DIRECT = [ @@ -18,14 +19,17 @@ var DIRECT = [ var NOP = function() {}; module.exports = function(ttyu_js_c) { - var ttyu = new ttyu_js_c(); + var emitter = new events.EventEmitter(); + var ttyu = new ttyu_js_c(function(ev) { + emitter.emit(ev.type, ev); + }); var ttyutil = { on: function(ev, listener) { if(ev === ttyutil.EVENT.SIGNAL) { signal.on(ttyu, ttyu, listener); } else if(ev in Const.Event && listener instanceof Function) { - ttyu.on(Const.Event[ev], listener); + emitter.on(ev, listener); } return ttyutil; }, @@ -88,12 +92,11 @@ module.exports = function(ttyu_js_c) { if(ev === ttyutil.EVENT.SIGNAL) { signal.off(ttyu, listener); } else if(ev in Const.Event && listener instanceof Function) { - ttyu.off(Const.Event[ev], listener); + emitter.removeListener(ev, listener); } return ttyutil; }; - ttyutil.SIGNAL = { SIGINT: "SIGINT", SIGTERM: "SIGTERM", diff --git a/src/core/ttyu.cc b/src/core/ttyu.cc index f9e9abf..52749aa 100644 --- a/src/core/ttyu.cc +++ b/src/core/ttyu.cc @@ -23,28 +23,11 @@ */ #include -int ttyu_ee_cb_call(ee__listener_t *l, v8::Local data) { - v8::Local args[] = { - data - }; - int count = 0; - do { - if (l->cb) { - l->cb->Call(1, args); - ++count; - } - } while ((l = l->next)); - return count; -} - -int ttyu_ee_compare(EE_CB_ARG(cb1), EE_CB_ARG(cb2)) { - return static_cast(cb1->GetFunction() == cb2->GetFunction()); -} - NAN_METHOD(ttyu_js_c::js_new) { NanScope(); ttyu_js_c *obj = new ttyu_js_c(); obj->Wrap(args.This()); + obj->emitter = new NanCallback(v8::Local::Cast(args[0])); NanReturnThis(); } @@ -65,8 +48,6 @@ void ttyu_js_c::init(v8::Handle exports, EXPORT_METHOD(tpl, "start", js_start); EXPORT_METHOD(tpl, "stop", js_stop); - EXPORT_METHOD(tpl, "on", js_on); - EXPORT_METHOD(tpl, "off", js_off); EXPORT_METHOD(tpl, "emit", js_emit); EXPORT_METHOD(tpl, "write", js_write); EXPORT_METHOD(tpl, "getrunning", js_running); diff --git a/src/unix/main.cc b/src/unix/main.cc index faa7922..6f92ce6 100644 --- a/src/unix/main.cc +++ b/src/unix/main.cc @@ -24,12 +24,10 @@ #include ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), mode(MODE_VT100), - x(0), y(0) { - ee_init(&emitter, ttyu_ee_cb_call, ttyu_ee_compare); -} + x(0), y(0) { } ttyu_js_c::~ttyu_js_c() { running = FALSE; stop = TRUE; - ee_destroy(&emitter); + delete emitter; } diff --git a/src/unix/off.cc b/src/unix/off.cc deleted file mode 100644 index 756ec56..0000000 --- a/src/unix/off.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* ttyutil - unix/off.cc - * https://github.com/clidejs/ttyutil - * - * Copyright Bernhard Bücherl - * - * 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. - */ -#include - -NAN_METHOD(ttyu_js_c::js_off) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - MUTEX_LOCK(&obj->emitlock, { - ee_off(&obj->emitter, args[0]->Int32Value(), - new NanCallback(v8::Local::Cast(args[1]))); - }); - NanReturnThis(); -} diff --git a/src/unix/on.cc b/src/unix/on.cc deleted file mode 100644 index 08b8194..0000000 --- a/src/unix/on.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* ttyutil - unix/on.cc - * https://github.com/clidejs/ttyutil - * - * Copyright Bernhard Bücherl - * - * 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. - */ -#include - -NAN_METHOD(ttyu_js_c::js_on) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - MUTEX_LOCK(&obj->emitlock, { - ee_on(&obj->emitter, args[0]->Int32Value(), - new NanCallback(v8::Local::Cast(args[1]))); - }); - NanReturnThis(); -} diff --git a/src/unix/worker.cc b/src/unix/worker.cc index 23809b4..cc5f7ba 100644 --- a/src/unix/worker.cc +++ b/src/unix/worker.cc @@ -55,14 +55,6 @@ void ttyu_worker_c::HandleOKCallback() { i < emit_stack.size(); ++i) { ttyu_event_t event = emit_stack[i]; SDBG("::HandleOKCallback %d %d", i, event.type); - - MUTEX_LOCK(&obj->emitlock, { - if (ee_count(&obj->emitter, event.type) == 0 || - event.type == EVENT_NONE) { - continue; // fast skip - } - }); - v8::Local jsobj = NanNew(); switch (event.type) { case EVENT_RESIZE: @@ -111,9 +103,10 @@ void ttyu_worker_c::HandleOKCallback() { break; } - MUTEX_LOCK(&obj->emitlock, { - ee_emit(&obj->emitter, event.type, jsobj); - }); + v8::Local args[] = { + jsobj + }; + obj->emitter->Call(1, args); } emit_stack.clear(); obj->check_queue(); diff --git a/src/win/emit.cc b/src/win/emit.cc index c947a5c..9474dd7 100644 --- a/src/win/emit.cc +++ b/src/win/emit.cc @@ -27,7 +27,6 @@ NAN_METHOD(ttyu_js_c::js_emit) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); THROW_IF_STOPPED(obj); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); if (obj->running) { int ev = args[0]->Int32Value(); INPUT_RECORD in[1]; diff --git a/src/win/main.cc b/src/win/main.cc index 0905879..a0ffe80 100644 --- a/src/win/main.cc +++ b/src/win/main.cc @@ -23,12 +23,9 @@ */ #include -ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), worker(this), top(0) { - ee_init(&emitter, ttyu_ee_cb_call, ttyu_ee_compare); -} +ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), worker(this), top(0) { } ttyu_js_c::~ttyu_js_c() { running = FALSE; stop = TRUE; - ee_destroy(&emitter); } diff --git a/src/win/off.cc b/src/win/off.cc deleted file mode 100644 index 8c65cec..0000000 --- a/src/win/off.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* ttyutil - win/off.cc - * https://github.com/clidejs/ttyutil - * - * Copyright Bernhard Bücherl - * - * 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. - */ -#include - -NAN_METHOD(ttyu_js_c::js_off) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - uv_mutex_lock(&obj->emitlock); - ee_off(&obj->emitter, args[0]->Int32Value(), - new NanCallback(v8::Local::Cast(args[1]))); - uv_mutex_unlock(&obj->emitlock); - NanReturnThis(); -} diff --git a/src/win/on.cc b/src/win/on.cc deleted file mode 100644 index 9de2518..0000000 --- a/src/win/on.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* ttyutil - win/on.cc - * https://github.com/clidejs/ttyutil - * - * Copyright Bernhard Bücherl - * - * 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. - */ -#include - -NAN_METHOD(ttyu_js_c::js_on) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - uv_mutex_lock(&obj->emitlock); - ee_on(&obj->emitter, args[0]->Int32Value(), - new NanCallback(v8::Local::Cast(args[1]))); - uv_mutex_unlock(&obj->emitlock); - NanReturnThis(); -} diff --git a/src/win/worker.cc b/src/win/worker.cc index 6c06f52..fe54b97 100644 --- a/src/win/worker.cc +++ b/src/win/worker.cc @@ -105,11 +105,6 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, void ttyu_worker_c::handle(ttyu_event_t *event) { DBG("::handle()"); - if (ee_count(&obj_->emitter, event->type) == 0 || obj_->stop || - !obj_->running) { - return; - } - v8::Local obj = NanNew(); switch (event->type) { case EVENT_RESIZE: @@ -154,9 +149,7 @@ void ttyu_worker_c::handle(ttyu_event_t *event) { event->type = EVENT_ERROR; break; } - uv_mutex_lock(&obj_->emitlock); - ee_emit(&obj_->emitter, event->type, obj); - uv_mutex_unlock(&obj_->emitlock); + // TODO emit } void ttyu_worker_c::Execute() { From cd8f1a528bf88bf90aaed6ec56cbea42d7546e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Thu, 18 Jun 2015 17:17:32 +0200 Subject: [PATCH 21/28] added example and colored output --- binding.gyp | 5 +- examples/colored-listener.js | 18 ++++ include/ttyu.h | 1 + include/unix.h | 13 +-- include/utils.h | 36 -------- lib/export.js | 115 ++++++++++++++++++++++- lib/utils.js | 15 +++ src/core/ttyu.cc | 1 + src/core/utilities.cc | 174 ----------------------------------- src/unix/beep.cc | 2 +- src/unix/clear.cc | 2 +- src/unix/colors.cc | 30 ++++++ src/unix/emit.cc | 2 +- src/unix/goto.cc | 2 +- src/unix/main.cc | 25 ++++- src/unix/resize.cc | 2 +- src/unix/start.cc | 3 +- src/unix/stop.cc | 3 +- src/unix/write.cc | 6 +- src/win/write.cc | 2 +- 20 files changed, 218 insertions(+), 239 deletions(-) create mode 100644 examples/colored-listener.js create mode 100644 lib/utils.js delete mode 100644 src/core/utilities.cc create mode 100644 src/unix/colors.cc diff --git a/binding.gyp b/binding.gyp index 65da137..a53877b 100644 --- a/binding.gyp +++ b/binding.gyp @@ -8,8 +8,7 @@ ], "sources": [ "src/core/ttyu_event.cc", - "src/core/ttyu.cc", - "src/core/utilities.cc" + "src/core/ttyu.cc" ], # pre install script @@ -33,6 +32,7 @@ "src/win/emit.cc", "src/win/goto.cc", "src/win/mode.cc", + "src/win/colors.cc", "src/win/resize.cc", "src/win/start.cc", "src/win/stop.cc", @@ -53,6 +53,7 @@ "src/unix/emit.cc", "src/unix/goto.cc", "src/unix/mode.cc", + "src/unix/colors.cc", "src/unix/resize.cc", "src/unix/start.cc", "src/unix/stop.cc", diff --git a/examples/colored-listener.js b/examples/colored-listener.js new file mode 100644 index 0000000..b6a4e86 --- /dev/null +++ b/examples/colored-listener.js @@ -0,0 +1,18 @@ +var ttyu = require("../lib/export")( + require("../build/Release/ttyu")); + +ttyu.start().bold().italic().underline(); +ttyu.on(ttyu.EVENT.KEY, out); +ttyu.on(ttyu.EVENT.MOUSEDOWN, out); + +function col() { + return Math.round(Math.random()*255); +} + +function out(ev) { + ttyu.fg(col()).bg(col()) + .write(JSON.stringify(ev) + "\r\n"); + if(ev.which == ttyu.WHICH.CHARX) { + ttyu.stop(); + } +}; diff --git a/include/ttyu.h b/include/ttyu.h index 592f65b..618097c 100644 --- a/include/ttyu.h +++ b/include/ttyu.h @@ -130,6 +130,7 @@ class ttyu_js_c : public node::ObjectWrap { static NAN_METHOD(js_setheight); static NAN_METHOD(js_resize); static NAN_METHOD(js_mode); + static NAN_METHOD(js_colors); static NAN_METHOD(js_setx); static NAN_METHOD(js_getx); static NAN_METHOD(js_sety); diff --git a/include/unix.h b/include/unix.h index 88c3d6c..83d2762 100644 --- a/include/unix.h +++ b/include/unix.h @@ -28,6 +28,7 @@ #define NCURSES_OPAQUE FALSE #include #include +#include #include #include #include @@ -101,6 +102,7 @@ int ttyu_unix_which(int c); int ttyu_unix_key(int which); +TTYU_INLINE int ttyu_get_colors(); class ttyu_worker_c : public NanAsyncWorker { public: @@ -115,12 +117,6 @@ class ttyu_worker_c : public NanAsyncWorker { std::vector emit_stack; }; -typedef struct ttyu_listener_s { - int type; - NanCallback *cb; - bool on; -} ttyu_listener_t; - #define PLATFORM_DEPENDENT_FIELDS \ void check_queue(); \ static void curses_thread_func(void *that); \ @@ -129,16 +125,15 @@ typedef struct ttyu_listener_s { uv_thread_t curses_thread; \ WINDOW *win; \ uv_barrier_t barrier; \ - uv_mutex_t emitlock; \ uv_mutex_t emitstacklock; \ uv_mutex_t ungetlock; \ uv_cond_t condition; \ int mode; \ int x; \ int y; \ + int colors; \ bool worker_run; \ std::queue unget_stack; \ - std::vector emit_stack; \ - std::vector listener_modifiers + std::vector emit_stack #endif // INCLUDE_UNIX_H_# diff --git a/include/utils.h b/include/utils.h index 5f58f4e..dca4f53 100644 --- a/include/utils.h +++ b/include/utils.h @@ -25,8 +25,6 @@ #ifndef INCLUDE_UTILS_H_ #define INCLUDE_UTILS_H_ -#include - #define EXPORT_METHOD(tpl, name, cb) do { \ v8::Local t = NanNew(cb); \ tpl->InstanceTemplate()->Set(NanNew(name), \ @@ -50,38 +48,4 @@ # define TTYU_INLINE inline #endif -#define WIN_COLORS 16 - -#define COLORS_ARRAY(XX, i) \ - XX(0, i, 0x000000) \ - XX(1, i, 0x800000) \ - XX(2, i, 0x008000) \ - XX(3, i, 0x808000) \ - XX(4, i, 0x000080) \ - XX(5, i, 0x800080) \ - XX(6, i, 0x008080) \ - XX(7, i, 0xc0c0c0) \ - XX(8, i, 0x808080) \ - XX(9, i, 0xff0000) \ - XX(10, i, 0x00ff00) \ - XX(11, i, 0xffff00) \ - XX(12, i, 0x0000ff) \ - XX(13, i, 0xff00ff) \ - XX(14, i, 0x00ffff) \ - XX(15, i, 0xffffff) - -TTYU_INLINE uint32_t util_colormatch(uint8_t i); -TTYU_INLINE int16_t util_rgbi2term(int16_t r, int16_t g, int16_t b); -TTYU_INLINE int16_t util_rgbi2win(int16_t r, int16_t g, int16_t b); -TTYU_INLINE char *util_render(const char *ch, int16_t fg, int16_t bg); -TTYU_INLINE int16_t util_parse_dec(char d); -TTYU_INLINE int16_t util_parse_hex(char h); -TTYU_INLINE uint32_t util_term2argb(int16_t t); -TTYU_INLINE int16_t util_rgb2term(const char *rgb); -TTYU_INLINE int16_t util_hex2term(const char *hex); -TTYU_INLINE int16_t util_color(const char *c); -TTYU_INLINE int util_max(int a, int b); -TTYU_INLINE int util_min(int a, int b); -TTYU_INLINE int util_abs(int a); - #endif // INCLUDE_UTILS_H_ diff --git a/lib/export.js b/lib/export.js index 4bd634f..6cb80d7 100644 --- a/lib/export.js +++ b/lib/export.js @@ -1,13 +1,14 @@ var events = require("events"); var Const = require("./const"); var signal = require("./signal"); +var utils = require("./utils"); var DIRECT = [ - "write", "running", "width", "height", "resize", "mode", + "colors", "x", "y", "goto", @@ -20,6 +21,7 @@ var NOP = function() {}; module.exports = function(ttyu_js_c) { var emitter = new events.EventEmitter(); + var fg, bg, bold, italic, underline, reverse; var ttyu = new ttyu_js_c(function(ev) { emitter.emit(ev.type, ev); }); @@ -35,7 +37,7 @@ module.exports = function(ttyu_js_c) { }, removeListener: off, off: off, - emit:function(ev) { + emit: function(ev) { switch(ev.type) { case ttyutil.EVENT.SIGNAL: signal.emit(ev.signal); @@ -55,17 +57,110 @@ module.exports = function(ttyu_js_c) { // ERROR, RESIZE break; } + }, + reset: reset, + fg: function(r,g,b) { + if(arguments.length == 3) { + fg = utils.rgb(r,g,b); + } else if(arguments.length == 1) { + if(typeof r === "number") { + fg = r; + } else { + fg = utils.hex(r); + } + } else { + fg = -1; + } + return ttyutil; + }, + bg: function(r,g,b) { + if(arguments.length == 3) { + bg = utils.rgb(r,g,b); + } else if(arguments.length == 1) { + if(typeof r === "number") { + bg = r; + } else { + bg = utils.hex(r); + } + } else { + bg = -1; + } + return ttyutil; + }, + bold: function(flag) { + if(typeof flag === "boolean") { + bold = flag; + } else if(typeof flag === "undefined") { + bold = true; + } + return ttyutil; + }, + italic: function(flag) { + if(typeof flag === "boolean") { + italic = flag; + } else if(typeof flag === "undefined") { + italic = true; + } + return ttyutil; + }, + underline: function(flag) { + if(typeof flag === "boolean") { + underline = flag; + } else if(typeof flag === "undefined") { + underline = true; + } + return ttyutil; + }, + reverse: function(flag) { + if(typeof flag === "boolean") { + reverse = flag; + } else if(typeof flag === "undefined") { + reverse = true; + } + return ttyutil; + }, + inverse: function() { + return ttyutil; + }, + write: function(chunk) { + format = "%s"; + if(fg != -1) + format = "\x1b[38;5;" + fg + "m" + format + "\x1b[39m"; + if(bg != -1) + format = "\x1b[48;5;" + bg + "m" + format + "\x1b[49m"; + if(bold) + format = "\x1b[1m" + format; + else + format = "\x1b[22m" + format; + if(italic) + format = "\x1b[3m" + format; + else + format = "\x1b[23m" + format; + if(underline) + format = "\x1b[4m" + format; + else + format = "\x1b[24m" + format; + ttyu.write(reverse ? rev(chunk) : chunk, format); + return ttyutil; } - } + }; for(var i = 0; i < DIRECT.length; ++i) { applyDirect(DIRECT[i]); } + function rev(str) { + for(var i = str.length - 1, o = ""; i >= 0; o += str[i--]); + return o; + } + function applyDirect(d) { if(d in ttyu) { ttyutil[d] = function() { - ttyu[d].apply(ttyu, arguments); + var ret = ttyu[d].apply(ttyu, arguments); + if(ret) + return ret; + return ttyutil; } } else if("set" + d in ttyu) { Object.defineProperty(ttyutil, d, { @@ -88,6 +183,16 @@ module.exports = function(ttyu_js_c) { } } + function reset() { + fg = -1; + bg = -1; + bold = false; + italic = false; + underline = false; + reverse = false; + return ttyutil; + } + function off(ev, listener) { if(ev === ttyutil.EVENT.SIGNAL) { signal.off(ttyu, listener); @@ -133,5 +238,5 @@ module.exports = function(ttyu_js_c) { }; }; - return ttyutil; + return reset(); // initial reset }; diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 0000000..b9b1857 --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,15 @@ +var utils = module.exports = { + rgb: function(r, g, b) { + return utils.rgb5(r/51, g/51, b/51); + }, + + rgb5: function(r, g, b) { + return 16 + Math.round(r)*36 + Math.round(g)*6 + Math.round(b); + }, + + hex: function(c) { + c = c[0] === "#" ? c.substring(1) : c; + return utils.rgb(parseInt(c.substring(0, 2), 16), + parseInt(c.substring(2, 4), 16), parseInt(c.substring(4, 6), 16)); + } +}; diff --git a/src/core/ttyu.cc b/src/core/ttyu.cc index 52749aa..8713e69 100644 --- a/src/core/ttyu.cc +++ b/src/core/ttyu.cc @@ -57,6 +57,7 @@ void ttyu_js_c::init(v8::Handle exports, EXPORT_METHOD(tpl, "setheight", js_setheight); EXPORT_METHOD(tpl, "resize", js_resize); EXPORT_METHOD(tpl, "getmode", js_mode); + EXPORT_METHOD(tpl, "getcolors", js_colors); EXPORT_METHOD(tpl, "setx", js_setx); EXPORT_METHOD(tpl, "getx", js_getx); EXPORT_METHOD(tpl, "sety", js_sety); diff --git a/src/core/utilities.cc b/src/core/utilities.cc deleted file mode 100644 index 8a070a5..0000000 --- a/src/core/utilities.cc +++ /dev/null @@ -1,174 +0,0 @@ -/* ttyutil - util.cc - implements utility methods (see include/util.h) - * https://github.com/clidejs/ttyutil - * - * Copyright Bernhard Bücherl - * - * 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. - */ -#include - -TTYU_INLINE uint32_t util_colormatch(uint8_t i) { - #define XX(index, i, c) if (index == i) { return c; } - COLORS_ARRAY(XX, i); - #undef XX - return 0; -} - -TTYU_INLINE int16_t util_rgbi2term(int16_t r, int16_t g, int16_t b) { - return static_cast(r / 51 * 36 + g / 51 * 6 + b / 51 + 16); -} - -TTYU_INLINE int16_t util_rgbi2win(int16_t r, int16_t g, int16_t b) { - uint32_t match; - int16_t match_i = 0; - int match_diff = 256+256+256; - int diff; - unsigned char mr; - unsigned char mg; - unsigned char mb; - - for (uint8_t i = 0; i < 16; ++i) { - match = util_colormatch(i); - mb = ((match << 8) >> 24); - mg = ((match << 16) >> 24); - mr = ((match << 24) >> 24); - - diff = util_abs(mr - r) + util_abs(mg - g) + util_abs(mb - b); - if (diff <= match_diff) { - match_diff = diff; - match_i = i; - } - } - return match_i; -} - -TTYU_INLINE char *util_render(const char *ch, int16_t fg, int16_t bg) { - char *out = - reinterpret_cast(std::malloc(sizeof(char) * (strlen(ch) + 30))); - if (fg != -1 && bg != -1) { - sprintf(out, "\x1b[38;5;%dm\x1b[48;5;%dm%s\x1b[49m\x1b[39m", fg, bg, ch); - } else if (fg != -1) { - sprintf(out, "\x1b[38;5;%dm%s\x1b[39m", fg, ch); - } else if (bg != -1) { - sprintf(out, "\x1b[48;5;%dm%s\x1b[49m", bg, ch); - } else { - sprintf(out, "%s", ch); - } - return out; -} - -TTYU_INLINE int16_t util_parse_dec(char d) { - if (d >= '0' && d <= '9') { - return d - '0'; - } - return 0; -} - -TTYU_INLINE int16_t util_parse_hex(char h) { - if (h >= 'A' && h <= 'F') { - return h - 'A' + 10; - } else if (h >= 'a' && h <= 'f') { - return h - 'a' + 10; - } - return util_parse_dec(h); -} - -TTYU_INLINE uint32_t util_term2argb(int16_t t) { - uint32_t argb = 0; - t -= 16; - argb = ((t / 36) * 51) << 8; - argb += ((t % 36)/ 6) * 51; - argb = argb << 8; - argb += ((t % 36) % 6) * 51; - return argb; -} - -TTYU_INLINE int16_t util_rgb2term(const char *rgb) { - int16_t r = 0; - int16_t g = 0; - int16_t b = 0; - int16_t cur = 0; - int16_t pos = 0; - - for (uint8_t i = static_cast(strlen(rgb)); i; --i) { - if (rgb[i] == ',') { - ++cur; - pos = 0; - } else if (rgb[i] != ')') { - if (cur == 0) { - b += util_parse_dec(rgb[i]) * (pos == 2 ? 100 : (pos == 1 ? 10 : 1)); - } else if (cur == 1) { - g += util_parse_dec(rgb[i]) * (pos == 2 ? 100 : (pos == 1 ? 10 : 1)); - } else if (cur == 2) { - r += util_parse_dec(rgb[i]) * (pos == 2 ? 100 : (pos == 1 ? 10 : 1)); - } - ++pos; - } - } -#ifdef PLATFORM_WINDOWS - return util_rgbi2win(r, g, b); -#else - return util_rgbi2term(r, g, b); -#endif -} - -TTYU_INLINE int16_t util_hex2term(const char *hex) { - int16_t r = 0; - int16_t g = 0; - int16_t b = 0; - if (strlen(hex) == 6) { - r = util_parse_hex(hex[0]) * 16 + util_parse_hex(hex[1]); - g = util_parse_hex(hex[2]) * 16 + util_parse_hex(hex[3]); - b = util_parse_hex(hex[4]) * 16 + util_parse_hex(hex[5]); - } else if (strlen(hex) == 3) { - r = util_parse_hex(hex[0]); - g = util_parse_hex(hex[1]); - b = util_parse_hex(hex[2]); - r += r*16; - g += g*16; - b += b*16; - } -#ifdef PLATFORM_WINDOWS - return util_rgbi2win(r, g, b); -#else - return util_rgbi2term(r, g, b); -#endif -} - -TTYU_INLINE int16_t util_color(const char *c) { - if (c[0] == '#') { - return util_hex2term(&c[1]); - } else if (c[0] == 'r' && c[1] == 'g' && c[2] == 'b' && c[3] == '(') { - return util_rgb2term(&c[4]); - } else { - return util_hex2term(c); - } -} - -TTYU_INLINE int util_max(int a, int b) { - return (a > b) ? a : b; -} - -TTYU_INLINE int util_min(int a, int b) { - return (a > b) ? b : a; -} - -TTYU_INLINE int util_abs(int a) { - return (a < 0) ? a * -1 : a; -} diff --git a/src/unix/beep.cc b/src/unix/beep.cc index b6601c9..fd8c491 100644 --- a/src/unix/beep.cc +++ b/src/unix/beep.cc @@ -27,5 +27,5 @@ NAN_METHOD(ttyu_js_c::js_beep) { NanScope(); THROW_IF_STOPPED(ObjectWrap::Unwrap(args.This())); beep(); - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/unix/clear.cc b/src/unix/clear.cc index 8be0865..ebbb0df 100644 --- a/src/unix/clear.cc +++ b/src/unix/clear.cc @@ -44,5 +44,5 @@ NAN_METHOD(ttyu_js_c::js_clear) { } wmove(obj->win, obj->x, obj->y); wrefresh(obj->win); - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/unix/colors.cc b/src/unix/colors.cc new file mode 100644 index 0000000..a479fb8 --- /dev/null +++ b/src/unix/colors.cc @@ -0,0 +1,30 @@ +/* ttyutil - unix/colors.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_colors) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(obj->colors)); +} diff --git a/src/unix/emit.cc b/src/unix/emit.cc index 8468499..8b565ca 100644 --- a/src/unix/emit.cc +++ b/src/unix/emit.cc @@ -69,5 +69,5 @@ NAN_METHOD(ttyu_js_c::js_emit) { obj->unget_stack.push(event); }); } - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/unix/goto.cc b/src/unix/goto.cc index 5e00938..e0f6640 100644 --- a/src/unix/goto.cc +++ b/src/unix/goto.cc @@ -63,5 +63,5 @@ NAN_METHOD(ttyu_js_c::js_goto) { wmove(obj->win, obj->x, obj->y); wrefresh(obj->win); } - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/unix/main.cc b/src/unix/main.cc index 6f92ce6..504006c 100644 --- a/src/unix/main.cc +++ b/src/unix/main.cc @@ -24,10 +24,33 @@ #include ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), mode(MODE_VT100), - x(0), y(0) { } + x(0), y(0) { + colors = ttyu_get_colors(); +} ttyu_js_c::~ttyu_js_c() { running = FALSE; stop = TRUE; delete emitter; } + +TTYU_INLINE int ttyu_get_colors() { + FILE *pipe = popen("tput colors", "r"); + int out = 0; + if(!pipe) return out; + char buffer[64]; + std::string result = ""; + while(!feof(pipe)) { + if(fgets(buffer, 64, pipe) != NULL) + result += buffer; + } + int len = static_cast(result.size()); + for(int i = len; i > 0; --i) { + char d = result[i-1]; + if(d >= '0' && d <= '9') { + out += (d - '0') * pow(10, len - i - 1); + } + } + pclose(pipe); + return out; +} diff --git a/src/unix/resize.cc b/src/unix/resize.cc index 13ea4f5..ceccf46 100644 --- a/src/unix/resize.cc +++ b/src/unix/resize.cc @@ -65,5 +65,5 @@ NAN_METHOD(ttyu_js_c::js_resize) { THROW_IF_STOPPED(obj); resizeterm(args[0]->Int32Value(), args[1]->Int32Value()); wrefresh(obj->win); - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/unix/start.cc b/src/unix/start.cc index 8276003..c113a61 100644 --- a/src/unix/start.cc +++ b/src/unix/start.cc @@ -34,7 +34,6 @@ NAN_METHOD(ttyu_js_c::js_start) { obj->y = getcury(obj->win); uv_barrier_init(&obj->barrier, 3); - uv_mutex_init(&obj->emitlock); uv_mutex_init(&obj->emitstacklock); uv_mutex_init(&obj->ungetlock); uv_cond_init(&obj->condition); @@ -43,5 +42,5 @@ NAN_METHOD(ttyu_js_c::js_start) { obj->check_queue(); uv_barrier_wait(&obj->barrier); - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/unix/stop.cc b/src/unix/stop.cc index 8e80a15..a0e6c38 100644 --- a/src/unix/stop.cc +++ b/src/unix/stop.cc @@ -31,7 +31,6 @@ NAN_METHOD(ttyu_js_c::js_stop) { obj->stop = TRUE; uv_thread_join(&obj->curses_thread); - uv_mutex_destroy(&obj->emitlock); uv_mutex_destroy(&obj->emitstacklock); uv_mutex_destroy(&obj->ungetlock); uv_cond_destroy(&obj->condition); @@ -40,5 +39,5 @@ NAN_METHOD(ttyu_js_c::js_stop) { delwin(obj->win); DBG("window deleted"); - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/unix/write.cc b/src/unix/write.cc index 32e0a75..1931d1b 100644 --- a/src/unix/write.cc +++ b/src/unix/write.cc @@ -25,7 +25,9 @@ NAN_METHOD(ttyu_js_c::js_write) { NanScope(); - printf("%s", TTYU_TOSTRING(args[0])); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); + printf(TTYU_TOSTRING(args[1]), TTYU_TOSTRING(args[0])); refresh(); - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/win/write.cc b/src/win/write.cc index cb200d3..1a98f4e 100644 --- a/src/win/write.cc +++ b/src/win/write.cc @@ -26,5 +26,5 @@ NAN_METHOD(ttyu_js_c::js_write) { NanScope(); printf("%s", TTYU_TOSTRING(args[0])); - NanReturnThis(); + NanReturnUndefined(); } From 53c320ab72c773a88ae51a3e6cccb888bddfc8f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Tue, 23 Jun 2015 16:17:46 +0200 Subject: [PATCH 22/28] switching to tap for tests, working on windows implementation --- examples/colored-listener.js | 9 +- include/win.h | 4 + lib/export.js | 5 +- package.json | 8 +- src/core/ttyu.cc | 3 - src/unix/emit.cc | 4 +- src/win/beep.cc | 2 +- src/win/clear.cc | 2 +- src/win/colors.cc | 32 +++++ src/win/emit.cc | 3 +- src/win/goto.cc | 2 +- src/win/main.cc | 5 +- src/win/resize.cc | 2 +- src/win/start.cc | 2 +- src/win/stop.cc | 3 +- src/win/worker.cc | 5 +- src/win/write.cc | 1 + tests/key.js | 229 +++++++++++++++-------------------- tests/mouse-down.js | 71 ----------- tests/mouse.js | 5 - tests/run.js | 13 -- tests/signal.js | 5 - tests/spec.js | 93 -------------- 23 files changed, 164 insertions(+), 344 deletions(-) create mode 100644 src/win/colors.cc delete mode 100644 tests/mouse-down.js delete mode 100644 tests/mouse.js delete mode 100644 tests/run.js delete mode 100644 tests/signal.js delete mode 100644 tests/spec.js diff --git a/examples/colored-listener.js b/examples/colored-listener.js index b6a4e86..ceae874 100644 --- a/examples/colored-listener.js +++ b/examples/colored-listener.js @@ -1,9 +1,8 @@ -var ttyu = require("../lib/export")( - require("../build/Release/ttyu")); +var ttyu = require("../index"); -ttyu.start().bold().italic().underline(); -ttyu.on(ttyu.EVENT.KEY, out); -ttyu.on(ttyu.EVENT.MOUSEDOWN, out); +ttyu.start().bold().italic().underline() + .on(ttyu.EVENT.KEY, out) + .on(ttyu.EVENT.MOUSEDOWN, out); function col() { return Math.round(Math.random()*255); diff --git a/include/win.h b/include/win.h index f3dbfe9..91bfa61 100644 --- a/include/win.h +++ b/include/win.h @@ -29,6 +29,10 @@ #define WIN_BUFFER_SIZE 128 +#ifndef MOUSE_HWHEELED +#define MOUSE_HWHEELED 0x0008 +#endif + // worker class, heavily inspired by nan's NanAsyncProgressWorker class ttyu_worker_c : public NanAsyncWorker { public: diff --git a/lib/export.js b/lib/export.js index 6cb80d7..49f79c6 100644 --- a/lib/export.js +++ b/lib/export.js @@ -23,8 +23,10 @@ module.exports = function(ttyu_js_c) { var emitter = new events.EventEmitter(); var fg, bg, bold, italic, underline, reverse; var ttyu = new ttyu_js_c(function(ev) { + console.log("emit " + JSON.stringify(ev)); emitter.emit(ev.type, ev); }); + emitter.setMaxListeners(100); var ttyutil = { on: function(ev, listener) { @@ -119,9 +121,6 @@ module.exports = function(ttyu_js_c) { } return ttyutil; }, - inverse: function() { - return ttyutil; - }, write: function(chunk) { format = "%s"; if(fg != -1) diff --git a/package.json b/package.json index 1ffebb5..debabc8 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "lint": "./deps/styleguide/cpplint/cpplint.py --extensions=h,cc --filter=-runtime/printf include/* src/core/* src/unix/* src/win/*", - "test": "./node_modules/.bin/mocha tests/run --reporter min" + "test": "tap tests/*.js" }, "repository": { "type": "git", @@ -29,11 +29,9 @@ "nan": "1.8.4" }, "devDependencies": { - "chai": "3.0.0", - "it-each": "0.3.1", - "mocha": "2.2.5", "node-gyp": "2.0.1", - "node-is": "0.5.2" + "node-is": "0.5.2", + "tap": "^1.2.1" }, "engines": { "node": ">=0.8.0" diff --git a/src/core/ttyu.cc b/src/core/ttyu.cc index 8713e69..04cb420 100644 --- a/src/core/ttyu.cc +++ b/src/core/ttyu.cc @@ -65,9 +65,6 @@ void ttyu_js_c::init(v8::Handle exports, EXPORT_METHOD(tpl, "goto", js_goto); EXPORT_METHOD(tpl, "beep", js_beep); EXPORT_METHOD(tpl, "clear", js_clear); -/* - EXPORT_METHOD(tpl, "color", js_color); - EXPORT_METHOD(tpl, "prepare", js_prepare);*/ module->Set(NanNew("exports"), tpl->GetFunction()); } diff --git a/src/unix/emit.cc b/src/unix/emit.cc index 8b565ca..89846ba 100644 --- a/src/unix/emit.cc +++ b/src/unix/emit.cc @@ -26,13 +26,14 @@ NAN_METHOD(ttyu_js_c::js_emit) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); int arg0 = args[0]->Int32Value(); int arg1 = args[1]->Int32Value(); int arg2 = args[2]->Int32Value(); int arg3 = args[3]->Int32Value(); int arg4 = args[4]->Int32Value(); ttyu_event_t event; - THROW_IF_STOPPED(obj); + SDBG("__%d", arg1); switch (arg0) { case EVENT_KEY: { int c = -1; @@ -50,6 +51,7 @@ NAN_METHOD(ttyu_js_c::js_emit) { } else { c = ttyu_unix_key(arg1); } // TODO(@bbuecherl) v + SDBG("___%d", c); ttyu_event_create_key(&event, arg2, &ch, c, arg1); } break; case EVENT_MOUSEDOWN: diff --git a/src/win/beep.cc b/src/win/beep.cc index 83ed6db..8b3a9c8 100644 --- a/src/win/beep.cc +++ b/src/win/beep.cc @@ -28,5 +28,5 @@ NAN_METHOD(ttyu_js_c::js_beep) { ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); THROW_IF_STOPPED(obj); // TODO(@bbuecherl) - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/win/clear.cc b/src/win/clear.cc index 81c471f..737aee9 100644 --- a/src/win/clear.cc +++ b/src/win/clear.cc @@ -28,5 +28,5 @@ NAN_METHOD(ttyu_js_c::js_clear) { ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); THROW_IF_STOPPED(obj); // TODO(@bbuecherl) - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/win/colors.cc b/src/win/colors.cc new file mode 100644 index 0000000..e132c75 --- /dev/null +++ b/src/win/colors.cc @@ -0,0 +1,32 @@ +/* ttyutil - win/colors.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +NAN_METHOD(ttyu_js_c::js_colors) { + NanScope(); + ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); + THROW_IF_STOPPED(obj); + // TODO(@bbuecherl) + NanReturnUndefined(); +} diff --git a/src/win/emit.cc b/src/win/emit.cc index 9474dd7..f5b4ace 100644 --- a/src/win/emit.cc +++ b/src/win/emit.cc @@ -25,6 +25,7 @@ NAN_METHOD(ttyu_js_c::js_emit) { NanScope(); + DBG("::js_emit"); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); THROW_IF_STOPPED(obj); if (obj->running) { @@ -103,5 +104,5 @@ NAN_METHOD(ttyu_js_c::js_emit) { WriteConsoleInput(obj->hin, in, 1, &w); } } - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/win/goto.cc b/src/win/goto.cc index 482f8f2..bc36849 100644 --- a/src/win/goto.cc +++ b/src/win/goto.cc @@ -60,5 +60,5 @@ NAN_METHOD(ttyu_js_c::js_goto) { ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); THROW_IF_STOPPED(obj); // TODO(@bbuecherl) - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/win/main.cc b/src/win/main.cc index a0ffe80..659715e 100644 --- a/src/win/main.cc +++ b/src/win/main.cc @@ -23,9 +23,12 @@ */ #include -ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), worker(this), top(0) { } +ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), worker(this), top(0) { + DBG("::ttyu_js_c"); +} ttyu_js_c::~ttyu_js_c() { + DBG("::~ttyu_js_c"); running = FALSE; stop = TRUE; } diff --git a/src/win/resize.cc b/src/win/resize.cc index 8e465ae..2992000 100644 --- a/src/win/resize.cc +++ b/src/win/resize.cc @@ -50,5 +50,5 @@ NAN_METHOD(ttyu_js_c::js_setheight) { NAN_METHOD(ttyu_js_c::js_resize) { NanScope(); // TODO(@bbuecherl) - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/win/start.cc b/src/win/start.cc index b575a0c..1a4f0aa 100644 --- a/src/win/start.cc +++ b/src/win/start.cc @@ -54,5 +54,5 @@ NAN_METHOD(ttyu_js_c::js_start) { DBG(" destroy barrier"); uv_barrier_destroy(&obj->barrier); DBG(" destroyed barrier"); - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/win/stop.cc b/src/win/stop.cc index ac38068..1bc77d1 100644 --- a/src/win/stop.cc +++ b/src/win/stop.cc @@ -25,6 +25,7 @@ NAN_METHOD(ttyu_js_c::js_stop) { NanScope(); + DBG("::stop"); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); THROW_IF_STOPPED(obj); obj->running = FALSE; @@ -32,5 +33,5 @@ NAN_METHOD(ttyu_js_c::js_stop) { SetConsoleMode(obj->hin, obj->old_mode); - NanReturnThis(); + NanReturnUndefined(); } diff --git a/src/win/worker.cc b/src/win/worker.cc index fe54b97..0aa7f87 100644 --- a/src/win/worker.cc +++ b/src/win/worker.cc @@ -30,7 +30,7 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, INPUT_RECORD ir[WIN_BUFFER_SIZE]; DWORD i; DBG(" start"); - if (obj->err) { + /*if (obj->err) { ttyu_event_t *event = reinterpret_cast(malloc(sizeof(ttyu_event_t))); ttyu_event_create_error(event); @@ -40,7 +40,7 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, return FALSE; } obj->err->msg = NULL; - } + }*/ DBG(" read input"); @@ -86,6 +86,7 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, free(ch); + DBG(" sending key"); progress.send(const_cast(event)); } else if (WINDOW_BUFFER_SIZE_EVENT == ir[i].EventType) { ttyu_event_t *event = diff --git a/src/win/write.cc b/src/win/write.cc index 1a98f4e..aed0fdc 100644 --- a/src/win/write.cc +++ b/src/win/write.cc @@ -25,6 +25,7 @@ NAN_METHOD(ttyu_js_c::js_write) { NanScope(); + DBG("::write"); printf("%s", TTYU_TOSTRING(args[0])); NanReturnUndefined(); } diff --git a/tests/key.js b/tests/key.js index c65f1f2..7497c47 100644 --- a/tests/key.js +++ b/tests/key.js @@ -1,136 +1,105 @@ -require("it-each")({ testPerIteration: true}); +var ttyu = require("../index"); +var test = require("tap").test; var is = require("node-is"); -var Const = require("../lib/const"); - -var which = []; - -var keys = Object.keys(Const.Which); -for(var i = 0; i < keys.length; ++i) { - c = Const.Which[keys[i]]; - if(c != 19 && c != -1 && which.indexOf(c) === -1) { - which.push(c); - } -} var unix_required = [/* - Const.Which.BACK, - Const.Which.TAB, - Const.Which.CLEAR, - Const.Which.ENTER, - Const.Which.SHIFT, - Const.Which.SPACE, - Const.Which.PRIOR, - Const.Which.NEXT, - Const.Which.END, - Const.Which.HOME, - Const.Which.LEFT, - Const.Which.UP, - Const.Which.RIGHT, - Const.Which.DOWN, - Const.Which.PRINT, - Const.Which.INSERT, - Const.Which.DELETE, - Const.Which.HELP,*/ - Const.Which.CHAR0, - Const.Which.CHAR1, - Const.Which.CHAR2, - Const.Which.CHAR3, - Const.Which.CHAR4, - Const.Which.CHAR5, - Const.Which.CHAR6, - Const.Which.CHAR7, - Const.Which.CHAR8, - Const.Which.CHAR9, - Const.Which.CHARA, - Const.Which.CHARB, - Const.Which.CHARC, - Const.Which.CHARD, - Const.Which.CHARE, - Const.Which.CHARF, - Const.Which.CHARG, - Const.Which.CHARH, - Const.Which.CHARI, - Const.Which.CHARJ, - Const.Which.CHARK, - Const.Which.CHARL, - Const.Which.CHARM, - Const.Which.CHARN, - Const.Which.CHARO, - Const.Which.CHARP, - Const.Which.CHARQ, - Const.Which.CHARR, - Const.Which.CHARS, - Const.Which.CHART, - Const.Which.CHARU, - Const.Which.CHARV, - Const.Which.CHARW, - Const.Which.CHARX, - Const.Which.CHARY, - Const.Which.CHARZ/*, - Const.Which.F1, - Const.Which.F2, - Const.Which.F3, - Const.Which.F4, - Const.Which.F5, - Const.Which.F6, - Const.Which.F7, - Const.Which.F8, - Const.Which.F9, - Const.Which.F10, - Const.Which.F11, - Const.Which.F12, - Const.Which.F13, - Const.Which.F14, - Const.Which.F15, - Const.Which.F16, - Const.Which.F17, - Const.Which.F18, - Const.Which.F19, - Const.Which.F20, - Const.Which.F21, - Const.Which.F22, - Const.Which.F23, - Const.Which.F24, - Const.Which.BROWSER_REFRESH*/ + ttyu.WHICH.BACK, + ttyu.WHICH.TAB, + ttyu.WHICH.CLEAR, + ttyu.WHICH.ENTER, + ttyu.WHICH.SHIFT, + ttyu.WHICH.SPACE, + ttyu.WHICH.PRIOR, + ttyu.WHICH.NEXT, + ttyu.WHICH.END, + ttyu.WHICH.HOME, + ttyu.WHICH.LEFT, + ttyu.WHICH.UP, + ttyu.WHICH.RIGHT, + ttyu.WHICH.DOWN, + ttyu.WHICH.PRINT, + ttyu.WHICH.INSERT, + ttyu.WHICH.DELETE, + ttyu.WHICH.HELP,*/ + ttyu.WHICH.CHAR0, + ttyu.WHICH.CHAR1, + ttyu.WHICH.CHAR2, + ttyu.WHICH.CHAR3, + ttyu.WHICH.CHAR4, + ttyu.WHICH.CHAR5, + ttyu.WHICH.CHAR6, + ttyu.WHICH.CHAR7, + ttyu.WHICH.CHAR8, + ttyu.WHICH.CHAR9, + ttyu.WHICH.CHARA, + ttyu.WHICH.CHARB, + ttyu.WHICH.CHARC, + ttyu.WHICH.CHARD, + ttyu.WHICH.CHARE, + ttyu.WHICH.CHARF, + ttyu.WHICH.CHARG, + ttyu.WHICH.CHARH, + ttyu.WHICH.CHARI, + ttyu.WHICH.CHARJ, + ttyu.WHICH.CHARK, + ttyu.WHICH.CHARL, + ttyu.WHICH.CHARM, + ttyu.WHICH.CHARN, + ttyu.WHICH.CHARO, + ttyu.WHICH.CHARP, + ttyu.WHICH.CHARQ, + ttyu.WHICH.CHARR, + ttyu.WHICH.CHARS, + ttyu.WHICH.CHART, + ttyu.WHICH.CHARU, + ttyu.WHICH.CHARV, + ttyu.WHICH.CHARW, + ttyu.WHICH.CHARX, + ttyu.WHICH.CHARY, + ttyu.WHICH.CHARZ/*, + ttyu.WHICH.F1, + ttyu.WHICH.F2, + ttyu.WHICH.F3, + ttyu.WHICH.F4, + ttyu.WHICH.F5, + ttyu.WHICH.F6, + ttyu.WHICH.F7, + ttyu.WHICH.F8, + ttyu.WHICH.F9, + ttyu.WHICH.F10, + ttyu.WHICH.F11, + ttyu.WHICH.F12, + ttyu.WHICH.F13, + ttyu.WHICH.F14, + ttyu.WHICH.F15, + ttyu.WHICH.F16, + ttyu.WHICH.F17, + ttyu.WHICH.F18, + ttyu.WHICH.F19, + ttyu.WHICH.F20, + ttyu.WHICH.F21, + ttyu.WHICH.F22, + ttyu.WHICH.F23, + ttyu.WHICH.F24, + ttyu.WHICH.BROWSER_REFRESH*/ ]; -module.exports = function(ttyu, expect) { - describe("TTYUtil `key` event handling", function() { - describe(".which", function() { - before(function() { - ttyu.start(); - }); - - it.each(unix_required, "should recognize character #%s", - ['element'], function(element, next) { - this.timeout(500); - createTest(element, next); - ttyu.emit(ttyu.KeyEvent(element, 0)); - }); - - after(function() { - ttyu.stop(); - }); - - function createTest(element, callback) { - var test = function(ev) { - is.expect.type.of(ev).to.be.equal("Object"); - - if(process.platform !== "win32" && - unix_required.indexOf(element) === -1) { - expect([element, Const.Which.UNKNOWN]).to. - include(ev.which); - } else { - expect(ev.which).to.be.equal(element); - } - ttyu.off(ttyu.EVENT.KEY, test); - callback(); - }; - ttyu.on(ttyu.EVENT.KEY, test); - return test; - } - }); +test("key", function(t) { + t.plan(unix_required.length); + ttyu.start(); - // TODO (@bbuecherl) add tests for .ctrl - }); -}; + (function check(i, cb) { + var listener = function(ev) { + console.log(ev.which, unix_required[i], i) + t.equal(ev.which, unix_required[i], " which should be " + + unix_required[i]); + ttyu.off(ttyu.EVENT.KEY, listener); + if(i <= 0) cb(); else check(i - 1, cb); + }; + ttyu.on(ttyu.EVENT.KEY, listener); + console.log(i); + ttyu.emit(ttyu.KeyEvent(unix_required[i], 0)); + })(unix_required.length - 1, function() { + ttyu.stop(); + }) +}); diff --git a/tests/mouse-down.js b/tests/mouse-down.js deleted file mode 100644 index 36ff1af..0000000 --- a/tests/mouse-down.js +++ /dev/null @@ -1,71 +0,0 @@ -require("it-each")({ testPerIteration: true}); -var is = require("node-is"); -var Const = require("../const"); -var mouse = [Const.Mouse.LEFT, Const.Mouse.LEFT2, - Const.Mouse.LEFT3, Const.Mouse.RIGHT]; - -function makeEvent() { - return [mouse[Math.floor(Math.random() * mouse.length)], - Math.round(Math.random() * 60), Math.round(Math.random() * 15), 0]; -} - -var current = []; -var mevents = []; - -for(var i = 0; i < 100; ++i) { - mevents.push(makeEvent()); -} - -module.exports = function(TTYUtil, expect) { - return function() { - var ttyu; - - before(function() { - ttyu = new TTYUtil(); - ttyu.start(); - }); - - it.each(mevents, "should recognize mouse input: %s", ['element'], - function(element, next) { - this.timeout(500); - ttyu.on(TTYUtil.EVENT.MOUSEDOWN, createTest(element, next)); - ttyu.emit(TTYUtil.MouseEvent(TTYUtil.EVENT.MOUSEDOWN, element[0], - element[1], element[2], element[3])); - }); - - afterEach(function() { - var el; - while((el = current.pop())) { - ttyu.removeListener(TTYUtil.EVENT.MOUSEDOWN, el); - } - }) - - after(function(done) { - var el; - while((el = current.pop())) { - ttyu.removeListener(TTYUtil.EVENT.MOUSEDOWN, el); - } - setTimeout(function() { - ttyu.destroy(); - done(); - }, 100); - }); - - function createTest(element, callback) { - var test = function(ev) { - is.expect.type.of(ev).to.be.equal("Object"); - expect(ev.button).to.be.equal(element[0]); - expect(ev.x).to.be.equal(element[1]); - expect(ev.y).to.be.equal(element[2]); - expect(ev.ctrl).to.be.equal(element[3]); - ttyu.removeListener(TTYUtil.EVENT.MOUSEDOWN, test); - callback(); - }; - current.push(test); - - return test; - } - - // TODO (@bbuecherl) add tests for .ctrl - }; -}; diff --git a/tests/mouse.js b/tests/mouse.js deleted file mode 100644 index 4a0a495..0000000 --- a/tests/mouse.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = function(TTYUtil, expect) { - describe("TTYUtil `mouse` event handling", function() { - describe("MOUSEDOWN", require("./mouse-down")(TTYUtil, expect)); - }); -}; diff --git a/tests/run.js b/tests/run.js deleted file mode 100644 index 1fc038e..0000000 --- a/tests/run.js +++ /dev/null @@ -1,13 +0,0 @@ -var ttyu = require("../lib/export")(require("../build/Release/ttyu")); -var expect = require("chai").expect; - -// test specs -// require("./spec")(ttyu, expect); - -// test input listeners -require("./key")(ttyu, expect); -//require("./mouse")(ttyu, expect); -//require("./signal")(ttyu, expect); - -// test output functions -//require("./output")(ttyu, expect); diff --git a/tests/signal.js b/tests/signal.js deleted file mode 100644 index d968367..0000000 --- a/tests/signal.js +++ /dev/null @@ -1,5 +0,0 @@ -var is = require("node-is"); - -module.exports = function(TTYUtil, expect) { - -}; diff --git a/tests/spec.js b/tests/spec.js deleted file mode 100644 index 2ec4ed7..0000000 --- a/tests/spec.js +++ /dev/null @@ -1,93 +0,0 @@ -var is = require("node-is"); - -module.exports = function(TTYUtil, expect) { - describe("TTYUtil Specification", function() { - - describe("TTYUtil.prototype", function() { - var keys = Object.keys(TTYUtil.prototype); - - it("should have 13 enumerable properties", function() { - expect(keys.length).to.be.equal(13); - }); - - it("#on() should be an enumerable function", function() { - expect(keys.indexOf("on")).to.be.not.equal(-1); - is.expect.type.of(TTYUtil.prototype.on) - .to.be.equal("Function"); - }); - - it("#off() should be an enumerable function", function() { - expect(keys.indexOf("off")).to.be.not.equal(-1); - is.expect.type.of(TTYUtil.prototype.off) - .to.be.equal("Function"); - }); - - it("#removeListener() should be an enumerable function", - function() { - expect(keys.indexOf("removeListener")).to.be.not.equal(-1); - is.expect.type.of(TTYUtil.prototype.removeListener) - .to.be.equal("Function"); - }); - - it("#emit() should be an enumerable function", function() { - expect(keys.indexOf("emit")).to.be.not.equal(-1); - is.expect.type.of(TTYUtil.prototype.emit) - .to.be.equal("Function"); - }); - - it("#start() should be an enumerable function", function() { - expect(keys.indexOf("start")).to.be.not.equal(-1); - is.expect.type.of(TTYUtil.prototype.start) - .to.be.equal("Function"); - }); - - it("#pause() should be an enumerable function", function() { - expect(keys.indexOf("pause")).to.be.not.equal(-1); - is.expect.type.of(TTYUtil.prototype.pause) - .to.be.equal("Function"); - }); - - it("#destroy() should be an enumerable function", function() { - expect(keys.indexOf("destroy")).to.be.not.equal(-1); - is.expect.type.of(TTYUtil.prototype.destroy) - .to.be.equal("Function"); - }); - - it("#goto() should be an enumerable function", function() { - expect(keys.indexOf("goto")).to.be.not.equal(-1); - is.expect.type.of(TTYUtil.prototype.goto) - .to.be.equal("Function"); - }); - - it("#write() should be an enumerable function", function() { - expect(keys.indexOf("write")).to.be.not.equal(-1); - is.expect.type.of(TTYUtil.prototype.write) - .to.be.equal("Function"); - }); - - it("#prepare() should be an enumerable function", function() { - expect(keys.indexOf("prepare")).to.be.not.equal(-1); - is.expect.type.of(TTYUtil.prototype.prepare) - .to.be.equal("Function"); - }); - - it("#beep() should be an enumerable function", function() { - expect(keys.indexOf("beep")).to.be.not.equal(-1); - is.expect.type.of(TTYUtil.prototype.beep) - .to.be.equal("Function"); - }); - - it("#clear() should be an enumerable function", function() { - expect(keys.indexOf("clear")).to.be.not.equal(-1); - is.expect.type.of(TTYUtil.prototype.clear) - .to.be.equal("Function"); - }); - - it("#color() should be an enumerable function", function() { - expect(keys.indexOf("color")).to.be.not.equal(-1); - is.expect.type.of(TTYUtil.prototype.color) - .to.be.equal("Function"); - }); - }); - }); -}; From c1751ff027063b67a1f9a6413da8987bd5c00e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Sat, 27 Jun 2015 14:29:33 +0200 Subject: [PATCH 23/28] key tests passing on unix --- .gitmodules | 3 --- .travis.yml | 2 -- deps/styleguide | 1 - include/unix.h | 5 +++-- include/win.h | 2 +- lib/export.js | 1 - package.json | 8 +------- src/unix/curses.cc | 18 +++++++++--------- src/unix/emit.cc | 2 -- src/unix/worker.cc | 1 - tests/key.js | 43 +++++++++++++++++++------------------------ 11 files changed, 33 insertions(+), 53 deletions(-) delete mode 160000 deps/styleguide diff --git a/.gitmodules b/.gitmodules index 30fdbce..57032ee 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "deps/ncurses"] path = deps/ncurses url = git://ncurses.scripts.mit.edu/ncurses.git -[submodule "deps/styleguide"] - path = deps/styleguide - url = git://github.com/google/styleguide.git diff --git a/.travis.yml b/.travis.yml index 02c9971..9d76b96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,5 @@ node_js: - "iojs-v2.2.0" install: - npm install --verbose - - curl -G -v http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py -o cpplint.py script: - - npm run-script lint - npm test diff --git a/deps/styleguide b/deps/styleguide deleted file mode 160000 index 43d738a..0000000 --- a/deps/styleguide +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 43d738ab8bb0c797f78506945729946aacbab17d diff --git a/include/unix.h b/include/unix.h index 83d2762..7c2b6a4 100644 --- a/include/unix.h +++ b/include/unix.h @@ -1,5 +1,5 @@ /* ttyutil - unix.h - additional header file for unixy systems, - * impementation in src/unix.cc + * impementation in src/unix/. * https://github.com/clidejs/ttyutil * * Copyright Bernhard Bücherl @@ -120,7 +120,8 @@ class ttyu_worker_c : public NanAsyncWorker { #define PLATFORM_DEPENDENT_FIELDS \ void check_queue(); \ static void curses_thread_func(void *that); \ - static int curses_threaded_func(WINDOW *win, void *that); \ + static int curses_threaded_func_thread(WINDOW *win, void *that); \ + static int curses_threaded_func(WINDOW *win, ttyu_js_c *obj); \ \ uv_thread_t curses_thread; \ WINDOW *win; \ diff --git a/include/win.h b/include/win.h index 91bfa61..64f9b33 100644 --- a/include/win.h +++ b/include/win.h @@ -1,5 +1,5 @@ /* ttyutil - win.h - additional header file for windows systems, - * implementation in src/win.cc + * implementation in src/win/. * https://github.com/clidejs/ttyutil * * Copyright Bernhard Bücherl diff --git a/lib/export.js b/lib/export.js index 49f79c6..33411da 100644 --- a/lib/export.js +++ b/lib/export.js @@ -23,7 +23,6 @@ module.exports = function(ttyu_js_c) { var emitter = new events.EventEmitter(); var fg, bg, bold, italic, underline, reverse; var ttyu = new ttyu_js_c(function(ev) { - console.log("emit " + JSON.stringify(ev)); emitter.emit(ev.type, ev); }); emitter.setMaxListeners(100); diff --git a/package.json b/package.json index debabc8..7a468f8 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,7 @@ "description": "cross-platform terminal utilities", "main": "index.js", "scripts": { - "lint": "./deps/styleguide/cpplint/cpplint.py --extensions=h,cc --filter=-runtime/printf include/* src/core/* src/unix/* src/win/*", - "test": "tap tests/*.js" + "test": "node tests/*.js" }, "repository": { "type": "git", @@ -28,11 +27,6 @@ "dependencies": { "nan": "1.8.4" }, - "devDependencies": { - "node-gyp": "2.0.1", - "node-is": "0.5.2", - "tap": "^1.2.1" - }, "engines": { "node": ">=0.8.0" } diff --git a/src/unix/curses.cc b/src/unix/curses.cc index ae29492..081c3d5 100644 --- a/src/unix/curses.cc +++ b/src/unix/curses.cc @@ -23,9 +23,7 @@ */ #include -int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { - ttyu_js_c *obj = static_cast(that); - +int ttyu_js_c::curses_threaded_func(WINDOW *win, ttyu_js_c *obj) { int c = wgetch(win); MEVENT mev; ttyu_event_t event; @@ -202,6 +200,13 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, void *that) { return 0; } +int ttyu_js_c::curses_threaded_func_thread(WINDOW *win, void *that) { + ttyu_js_c *obj = static_cast(that); + uv_barrier_wait(&obj->barrier); + while(curses_threaded_func(win, obj) == 0 && obj->running) usleep(100); + return 0; +}; + void ttyu_js_c::curses_thread_func(void *that) { ttyu_js_c *obj = static_cast(that); @@ -212,10 +217,5 @@ void ttyu_js_c::curses_thread_func(void *that) { nodelay(obj->win, TRUE); mouseinterval(FALSE); - uv_barrier_wait(&obj->barrier); - - while (obj->running && !obj->stop) { - use_window(obj->win, curses_threaded_func, that); - usleep(100); - } + use_window(obj->win, curses_threaded_func_thread, that); } diff --git a/src/unix/emit.cc b/src/unix/emit.cc index 89846ba..af5321e 100644 --- a/src/unix/emit.cc +++ b/src/unix/emit.cc @@ -33,7 +33,6 @@ NAN_METHOD(ttyu_js_c::js_emit) { int arg3 = args[3]->Int32Value(); int arg4 = args[4]->Int32Value(); ttyu_event_t event; - SDBG("__%d", arg1); switch (arg0) { case EVENT_KEY: { int c = -1; @@ -51,7 +50,6 @@ NAN_METHOD(ttyu_js_c::js_emit) { } else { c = ttyu_unix_key(arg1); } // TODO(@bbuecherl) v - SDBG("___%d", c); ttyu_event_create_key(&event, arg2, &ch, c, arg1); } break; case EVENT_MOUSEDOWN: diff --git a/src/unix/worker.cc b/src/unix/worker.cc index cc5f7ba..5de1197 100644 --- a/src/unix/worker.cc +++ b/src/unix/worker.cc @@ -54,7 +54,6 @@ void ttyu_worker_c::HandleOKCallback() { for (std::vector::size_type i = 0; i < emit_stack.size(); ++i) { ttyu_event_t event = emit_stack[i]; - SDBG("::HandleOKCallback %d %d", i, event.type); v8::Local jsobj = NanNew(); switch (event.type) { case EVENT_RESIZE: diff --git a/tests/key.js b/tests/key.js index 7497c47..d0a9040 100644 --- a/tests/key.js +++ b/tests/key.js @@ -1,8 +1,7 @@ var ttyu = require("../index"); -var test = require("tap").test; -var is = require("node-is"); +var assert = require("assert"); -var unix_required = [/* +var unix_required = [ ttyu.WHICH.BACK, ttyu.WHICH.TAB, ttyu.WHICH.CLEAR, @@ -20,7 +19,7 @@ var unix_required = [/* ttyu.WHICH.PRINT, ttyu.WHICH.INSERT, ttyu.WHICH.DELETE, - ttyu.WHICH.HELP,*/ + ttyu.WHICH.HELP, ttyu.WHICH.CHAR0, ttyu.WHICH.CHAR1, ttyu.WHICH.CHAR2, @@ -56,7 +55,7 @@ var unix_required = [/* ttyu.WHICH.CHARW, ttyu.WHICH.CHARX, ttyu.WHICH.CHARY, - ttyu.WHICH.CHARZ/*, + ttyu.WHICH.CHARZ, ttyu.WHICH.F1, ttyu.WHICH.F2, ttyu.WHICH.F3, @@ -81,25 +80,21 @@ var unix_required = [/* ttyu.WHICH.F22, ttyu.WHICH.F23, ttyu.WHICH.F24, - ttyu.WHICH.BROWSER_REFRESH*/ + ttyu.WHICH.BROWSER_REFRESH ]; +console.log("\r\n[tests/key]\r"); +ttyu.start(); -test("key", function(t) { - t.plan(unix_required.length); - ttyu.start(); - - (function check(i, cb) { - var listener = function(ev) { - console.log(ev.which, unix_required[i], i) - t.equal(ev.which, unix_required[i], " which should be " + - unix_required[i]); - ttyu.off(ttyu.EVENT.KEY, listener); - if(i <= 0) cb(); else check(i - 1, cb); - }; - ttyu.on(ttyu.EVENT.KEY, listener); - console.log(i); - ttyu.emit(ttyu.KeyEvent(unix_required[i], 0)); - })(unix_required.length - 1, function() { - ttyu.stop(); - }) +(function check(i, cb) { + var listener = function(ev) { + assert.equal(ev.which, unix_required[i], " which should be " + + unix_required[i]); + ttyu.off(ttyu.EVENT.KEY, listener); + if(i <= 0) cb(); else check(i - 1, cb); + }; + ttyu.on(ttyu.EVENT.KEY, listener); + ttyu.emit(ttyu.KeyEvent(unix_required[i], 0)); +})(unix_required.length - 1, function() { + ttyu.stop(); + console.log("[tests/key] passed\r"); }); From 01797678f07a5043a937174de17ddb92e67ca60e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Wed, 1 Jul 2015 18:11:04 +0200 Subject: [PATCH 24/28] improved function macro --- CHANGELOG.md | 8 +- binding.gyp | 2 + include/ttyu.h | 5 +- include/unix.h | 3 + include/utils.h | 51 ---------- lib/export.js | 64 ++++++++---- package.json | 2 +- src/core/ttyu.cc | 2 + src/unix/beep.cc | 8 +- src/unix/clear.cc | 17 ++-- src/unix/colors.cc | 8 +- src/unix/{start.cc => cursor.cc} | 30 ++---- src/unix/emit.cc | 13 +-- src/unix/goto.cc | 60 +++++------ src/unix/mode.cc | 8 +- src/unix/resize.cc | 43 +++----- src/unix/stop.cc | 30 +++--- src/unix/worker.cc | 54 +--------- src/unix/write.cc | 9 +- src/win/colors.cc | 1 - src/win/cursor.cc | 34 +++++++ src/win/stop.cc | 11 +- src/win/utils.cc | 4 - src/win/worker.cc | 169 ++++++++++--------------------- tests/index.js | 1 + tools/build.js | 2 +- 26 files changed, 243 insertions(+), 396 deletions(-) delete mode 100644 include/utils.h rename src/unix/{start.cc => cursor.cc} (66%) create mode 100644 src/win/cursor.cc create mode 100644 tests/index.js diff --git a/CHANGELOG.md b/CHANGELOG.md index e115f13..69069b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,13 +6,11 @@ - fullscreen detection - improve examples - add pixel rendering (e.g. for pngs) functions - - rework goto/write functionality - add X11 implementations to remove curses where possible + - add 256 color support to windows (using pixel rendering) ## 0.2.0 (WIP) - - added `.pause()` function - - renamed `.stop()` to `.destroy()` - all functions will throw now when the object was not started or already destroyed - added `.emit()` function @@ -21,10 +19,6 @@ - added `.type` property to event objects - iojs support -### TODO - - - fix segfault on unix - ## 0.1.2 - fixed infinite loop in helper method `util_rgb2term()` diff --git a/binding.gyp b/binding.gyp index a53877b..1d57cd2 100644 --- a/binding.gyp +++ b/binding.gyp @@ -29,6 +29,7 @@ "sources": [ "src/win/beep.cc", "src/win/clear.cc", + "src/win/cursor.cc", "src/win/emit.cc", "src/win/goto.cc", "src/win/mode.cc", @@ -50,6 +51,7 @@ "sources": [ "src/unix/beep.cc", "src/unix/clear.cc", + "src/unix/cursor.cc", "src/unix/emit.cc", "src/unix/goto.cc", "src/unix/mode.cc", diff --git a/include/ttyu.h b/include/ttyu.h index 618097c..68f2cc5 100644 --- a/include/ttyu.h +++ b/include/ttyu.h @@ -71,7 +71,7 @@ TTYU_INLINE ttyu_error_t _ERRMSG(int id) { #define ERRMSG(id) &_ERRMSG(id) #define THROW_IF_STOPPED(obj) if (!obj->running) { \ - return NanThrowError("Function requires ttyu to be running"); \ + return NanThrowError("Function requires ttyutil to be running"); \ } // key event structure @@ -138,8 +138,9 @@ class ttyu_js_c : public node::ObjectWrap { static NAN_METHOD(js_goto); static NAN_METHOD(js_beep); static NAN_METHOD(js_clear); - static NAN_METHOD(js_write); + static NAN_METHOD(js_hide); + static NAN_METHOD(js_show); ttyu_error_t *err; bool running; diff --git a/include/unix.h b/include/unix.h index 7c2b6a4..9b99b0d 100644 --- a/include/unix.h +++ b/include/unix.h @@ -100,6 +100,9 @@ \ XX(WHICH_SHIFT, 0, TRUE) +#define REFRESH_POSITION(obj) wmove(obj->win, obj->x, obj->y); \ + wrefresh(obj->win) + int ttyu_unix_which(int c); int ttyu_unix_key(int which); TTYU_INLINE int ttyu_get_colors(); diff --git a/include/utils.h b/include/utils.h deleted file mode 100644 index dca4f53..0000000 --- a/include/utils.h +++ /dev/null @@ -1,51 +0,0 @@ -/* ttyutil - util.h - header file to define utility methods, - * implementation in src/util.cc - * https://github.com/clidejs/ttyutil - * - * Copyright Bernhard Bücherl - * - * 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. - */ -#ifndef INCLUDE_UTILS_H_ -#define INCLUDE_UTILS_H_ - -#define EXPORT_METHOD(tpl, name, cb) do { \ - v8::Local t = NanNew(cb); \ - tpl->InstanceTemplate()->Set(NanNew(name), \ - t->GetFunction(), v8::ReadOnly); \ -} while (0) - -#define TTYU_TOSTRING(handle) \ - (new v8::String::Utf8Value(handle->ToString()))->operator*() - -#define MUTEX_LOCK(mutex, action) ({ \ - uv_mutex_lock(mutex); \ - action; \ - uv_mutex_unlock(mutex); \ -}) - -#if defined(__GNUC__) && !(defined(DEBUG) && DEBUG) -# define TTYU_INLINE inline __attribute__((always_inline)) -#elif defined(_MSC_VER) && !(defined(DEBUG) && DEBUG) -# define TTYU_INLINE __forceinline -#else -# define TTYU_INLINE inline -#endif - -#endif // INCLUDE_UTILS_H_ diff --git a/lib/export.js b/lib/export.js index 33411da..70e2c98 100644 --- a/lib/export.js +++ b/lib/export.js @@ -27,7 +27,7 @@ module.exports = function(ttyu_js_c) { }); emitter.setMaxListeners(100); - var ttyutil = { + var ttyutil = createObjectWithSealedMethods({ on: function(ev, listener) { if(ev === ttyutil.EVENT.SIGNAL) { signal.on(ttyu, ttyu, listener); @@ -141,25 +141,22 @@ module.exports = function(ttyu_js_c) { ttyu.write(reverse ? rev(chunk) : chunk, format); return ttyutil; } - }; - - for(var i = 0; i < DIRECT.length; ++i) { - applyDirect(DIRECT[i]); - } - - function rev(str) { - for(var i = str.length - 1, o = ""; i >= 0; o += str[i--]); - return o; - } + }); - function applyDirect(d) { + DIRECT.forEach(function(d) { if(d in ttyu) { - ttyutil[d] = function() { - var ret = ttyu[d].apply(ttyu, arguments); - if(ret) - return ret; - return ttyutil; - } + Object.defineProperty(ttyutil, d, { + __proto__: null, + value: function() { + var ret = ttyu[d].apply(ttyu, arguments); + if(ret) + return ret; + return ttyutil; + }, + configurable: false, + enumerable: false, + writeable: false + }); } else if("set" + d in ttyu) { Object.defineProperty(ttyutil, d, { __proto__: null, @@ -179,6 +176,29 @@ module.exports = function(ttyu_js_c) { writeable: false }); } + }); + + function createObjectWithSealedMethods(methods) { + var obj = {}; + var props = {}; + + for(var key in methods) { + props[key] = { + __proto__: null, + value: methods[key], + configurable: false, + enumerable: false, + writeable: false + }; + } + + Object.defineProperties(obj, props); + return obj; + } + + function rev(str) { + for(var i = str.length - 1, o = ""; i >= 0; o += str[i--]); + return o; } function reset() { @@ -236,5 +256,13 @@ module.exports = function(ttyu_js_c) { }; }; + // handle exits to clean up terminal + // TODO(@bbuecherl): only handle exits when no other listener is registered + /*process.on("exit", ttyutil.stop); + process.on("uncaughtException", ttyutil.stop); + Object.keys(ttyutil.SIGNAL).forEach(function(sig) { + process.on(sig, ttyutil.stop); + });*/ + return reset(); // initial reset }; diff --git a/package.json b/package.json index 7a468f8..5e6fa8c 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "cross-platform terminal utilities", "main": "index.js", "scripts": { - "test": "node tests/*.js" + "test": "node tests/index.js" }, "repository": { "type": "git", diff --git a/src/core/ttyu.cc b/src/core/ttyu.cc index 04cb420..c8a1ff8 100644 --- a/src/core/ttyu.cc +++ b/src/core/ttyu.cc @@ -65,6 +65,8 @@ void ttyu_js_c::init(v8::Handle exports, EXPORT_METHOD(tpl, "goto", js_goto); EXPORT_METHOD(tpl, "beep", js_beep); EXPORT_METHOD(tpl, "clear", js_clear); + EXPORT_METHOD(tpl, "hide", js_hide); + EXPORT_METHOD(tpl, "show", js_show); module->Set(NanNew("exports"), tpl->GetFunction()); } diff --git a/src/unix/beep.cc b/src/unix/beep.cc index fd8c491..1e23e41 100644 --- a/src/unix/beep.cc +++ b/src/unix/beep.cc @@ -23,9 +23,7 @@ */ #include -NAN_METHOD(ttyu_js_c::js_beep) { - NanScope(); - THROW_IF_STOPPED(ObjectWrap::Unwrap(args.This())); +JSFUNCTION(ttyu_js_c,js_beep, { + THROW_IF_STOPPED(that); beep(); - NanReturnUndefined(); -} +}) diff --git a/src/unix/clear.cc b/src/unix/clear.cc index ebbb0df..9f8dc3b 100644 --- a/src/unix/clear.cc +++ b/src/unix/clear.cc @@ -23,16 +23,14 @@ */ #include -NAN_METHOD(ttyu_js_c::js_clear) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_clear, { + THROW_IF_STOPPED(that); if (args.Length() == 4) { int x = args[0]->Int32Value(); int y = args[1]->Int32Value(); int w = args[2]->Int32Value(); int h = args[3]->Int32Value(); - wmove(obj->win, x, y); + wmove(that->win, x, y); for (int j = 0; j < h; ++j) { for (int i = 0; i < w; ++i) { std::cout << " "; @@ -40,9 +38,8 @@ NAN_METHOD(ttyu_js_c::js_clear) { } std::cout << "\r\n"; } else { - werase(obj->win); + werase(that->win); } - wmove(obj->win, obj->x, obj->y); - wrefresh(obj->win); - NanReturnUndefined(); -} + wmove(that->win, that->x, that->y); + wrefresh(that->win); +}); diff --git a/src/unix/colors.cc b/src/unix/colors.cc index a479fb8..7f3de57 100644 --- a/src/unix/colors.cc +++ b/src/unix/colors.cc @@ -23,8 +23,6 @@ */ #include -NAN_METHOD(ttyu_js_c::js_colors) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(obj->colors)); -} +JSFUNCTION(ttyu_js_c, js_colors, { + NanReturnValue(NanNew(that->colors)); +}) diff --git a/src/unix/start.cc b/src/unix/cursor.cc similarity index 66% rename from src/unix/start.cc rename to src/unix/cursor.cc index c113a61..2c5891b 100644 --- a/src/unix/start.cc +++ b/src/unix/cursor.cc @@ -1,4 +1,4 @@ -/* ttyutil - unix/start.cc +/* ttyutil - unix/cursor.cc * https://github.com/clidejs/ttyutil * * Copyright Bernhard Bücherl @@ -23,24 +23,12 @@ */ #include -NAN_METHOD(ttyu_js_c::js_start) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - obj->running = TRUE; - obj->stop = FALSE; - obj->worker_run = TRUE; - obj->win = initscr(); - obj->x = getcurx(obj->win); - obj->y = getcury(obj->win); +JSFUNCTION(ttyu_js_c, js_hide, { + THROW_IF_STOPPED(that); + // TODO(@bbuecherl) +}) - uv_barrier_init(&obj->barrier, 3); - uv_mutex_init(&obj->emitstacklock); - uv_mutex_init(&obj->ungetlock); - uv_cond_init(&obj->condition); - - uv_thread_create(&obj->curses_thread, ttyu_js_c::curses_thread_func, obj); - obj->check_queue(); - - uv_barrier_wait(&obj->barrier); - NanReturnUndefined(); -} +JSFUNCTION(ttyu_js_c, js_show, { + THROW_IF_STOPPED(that); + // TODO(@bbuecherl) +}) diff --git a/src/unix/emit.cc b/src/unix/emit.cc index af5321e..5f069ca 100644 --- a/src/unix/emit.cc +++ b/src/unix/emit.cc @@ -23,10 +23,8 @@ */ #include -NAN_METHOD(ttyu_js_c::js_emit) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_emit, { + THROW_IF_STOPPED(that); int arg0 = args[0]->Int32Value(); int arg1 = args[1]->Int32Value(); int arg2 = args[2]->Int32Value(); @@ -65,9 +63,8 @@ NAN_METHOD(ttyu_js_c::js_emit) { } if (event.type != EVENT_NONE) { - MUTEX_LOCK(&obj->ungetlock, { - obj->unget_stack.push(event); + MUTEX_LOCK(&that->ungetlock, { + that->unget_stack.push(event); }); } - NanReturnUndefined(); -} +}) diff --git a/src/unix/goto.cc b/src/unix/goto.cc index e0f6640..d4d28fb 100644 --- a/src/unix/goto.cc +++ b/src/unix/goto.cc @@ -23,45 +23,33 @@ */ #include -NAN_METHOD(ttyu_js_c::js_setx) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); - obj->x = args[0]->Int32Value(); - NanReturnUndefined(); -} +JSFUNCTION(ttyu_js_c, js_setx, { + THROW_IF_STOPPED(that); + that->x = args[0]->Int32Value(); + REFRESH_POSITION(that); +}) -NAN_METHOD(ttyu_js_c::js_getx) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); - NanReturnValue(NanNew(obj->x)); -} +JSFUNCTION(ttyu_js_c, js_getx, { + THROW_IF_STOPPED(that); + NanReturnValue(NanNew(that->x)); +}) -NAN_METHOD(ttyu_js_c::js_sety) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); - obj->y = args[0]->Int32Value(); - NanReturnUndefined(); -} +JSFUNCTION(ttyu_js_c, js_sety, { + THROW_IF_STOPPED(that); + that->y = args[0]->Int32Value(); + REFRESH_POSITION(that); +}) -NAN_METHOD(ttyu_js_c::js_gety) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); - NanReturnValue(NanNew(obj->y)); -} +JSFUNCTION(ttyu_js_c, js_gety, { + THROW_IF_STOPPED(that); + NanReturnValue(NanNew(that->y)); +}) -NAN_METHOD(ttyu_js_c::js_goto) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_goto, { + THROW_IF_STOPPED(that); if(args.Length() == 2) { - obj->x = args[0]->Int32Value(); - obj->y = args[1]->Int32Value(); - wmove(obj->win, obj->x, obj->y); - wrefresh(obj->win); + that->x = args[0]->Int32Value(); + that->y = args[1]->Int32Value(); + REFRESH_POSITION(that); } - NanReturnUndefined(); -} +}) diff --git a/src/unix/mode.cc b/src/unix/mode.cc index 0c77c10..0ec2309 100644 --- a/src/unix/mode.cc +++ b/src/unix/mode.cc @@ -23,8 +23,6 @@ */ #include -NAN_METHOD(ttyu_js_c::js_mode) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(obj->mode)); -} +JSFUNCTION(ttyu_js_c, js_mode, { + NanReturnValue(NanNew(that->mode)); +}) diff --git a/src/unix/resize.cc b/src/unix/resize.cc index ceccf46..6d28128 100644 --- a/src/unix/resize.cc +++ b/src/unix/resize.cc @@ -23,47 +23,36 @@ */ #include -NAN_METHOD(ttyu_js_c::js_getwidth) { - NanScope(); +JSFUNCTION(ttyu_js_c::js_getwidth, { struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); NanReturnValue(NanNew(w.ws_col)); -} +}) -NAN_METHOD(ttyu_js_c::js_getheight) { - NanScope(); +JSFUNCTION(ttyu_js_c::js_getheight, { struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); NanReturnValue(NanNew(w.ws_row)); -} +}) -NAN_METHOD(ttyu_js_c::js_setwidth) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_setwidth, { + THROW_IF_STOPPED(that); struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); resizeterm(args[0]->Int32Value(), w.ws_row); - wrefresh(obj->win); - NanReturnUndefined(); -} + wrefresh(that->win); +}) -NAN_METHOD(ttyu_js_c::js_setheight) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_setheight, { + THROW_IF_STOPPED(that); struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); resizeterm(w.ws_col, args[0]->Int32Value()); - wrefresh(obj->win); - NanReturnUndefined(); -} + wrefresh(that->win); +}) -NAN_METHOD(ttyu_js_c::js_resize) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_resize, { + THROW_IF_STOPPED(that); resizeterm(args[0]->Int32Value(), args[1]->Int32Value()); - wrefresh(obj->win); - NanReturnUndefined(); -} + wrefresh(that->win); +}) diff --git a/src/unix/stop.cc b/src/unix/stop.cc index a0e6c38..9be5be2 100644 --- a/src/unix/stop.cc +++ b/src/unix/stop.cc @@ -23,21 +23,19 @@ */ #include -NAN_METHOD(ttyu_js_c::js_stop) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); - obj->running = FALSE; - obj->stop = TRUE; +JSFUNCTION(ttyu_js_c, js_stop, { + if(that->running) { + that->running = FALSE; + that->stop = TRUE; - uv_thread_join(&obj->curses_thread); - uv_mutex_destroy(&obj->emitstacklock); - uv_mutex_destroy(&obj->ungetlock); - uv_cond_destroy(&obj->condition); - uv_barrier_destroy(&obj->barrier); - endwin(); - delwin(obj->win); + uv_thread_join(&that->curses_thread); + uv_mutex_destroy(&that->emitstacklock); + uv_mutex_destroy(&that->ungetlock); + uv_cond_destroy(&that->condition); + uv_barrier_destroy(&that->barrier); + endwin(); + delwin(that->win); - DBG("window deleted"); - NanReturnUndefined(); -} + DBG("window deleted"); + } +}) diff --git a/src/unix/worker.cc b/src/unix/worker.cc index 5de1197..535859d 100644 --- a/src/unix/worker.cc +++ b/src/unix/worker.cc @@ -53,59 +53,7 @@ void ttyu_worker_c::HandleOKCallback() { NanScope(); for (std::vector::size_type i = 0; i < emit_stack.size(); ++i) { - ttyu_event_t event = emit_stack[i]; - v8::Local jsobj = NanNew(); - switch (event.type) { - case EVENT_RESIZE: - jsobj->Set(NanNew("type"), EVENTSTRING_RESIZE); - break; - case EVENT_KEY: - jsobj->Set(NanNew("type"), EVENTSTRING_KEY); - jsobj->Set(NanNew("ctrl"), - NanNew(event.key->ctrl)); - jsobj->Set(NanNew("char"), - NanNew(event.key->c)); - jsobj->Set(NanNew("code"), - NanNew(event.key->code)); - jsobj->Set(NanNew("which"), - NanNew(event.key->which)); - break; - case EVENT_MOUSEDOWN: - case EVENT_MOUSEUP: - case EVENT_MOUSEMOVE: - case EVENT_MOUSEWHEEL: - case EVENT_MOUSEHWHEEL: - if (event.type == EVENT_MOUSEDOWN) { - jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEDOWN); - } else if (event.type == EVENT_MOUSEUP) { - jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEUP); - } else if (event.type == EVENT_MOUSEMOVE) { - jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEMOVE); - } else if (event.type == EVENT_MOUSEWHEEL) { - jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEWHEEL); - } else if (event.type == EVENT_MOUSEHWHEEL) { - jsobj->Set(NanNew("type"), EVENTSTRING_MOUSEHWHEEL); - } - jsobj->Set(NanNew("button"), - NanNew(event.mouse->button)); - jsobj->Set(NanNew("x"), - NanNew(event.mouse->x)); - jsobj->Set(NanNew("y"), - NanNew(event.mouse->y)); - jsobj->Set(NanNew("ctrl"), - NanNew(event.mouse->ctrl)); - break; - default: // EVENT_ERROR, EVENT_SIGNAL - jsobj->Set(NanNew("type"), EVENTSTRING_ERROR); - jsobj->Set(NanNew("error"), NanError("...")); - event.type = EVENT_ERROR; - break; - } - - v8::Local args[] = { - jsobj - }; - obj->emitter->Call(1, args); + EMIT_EVENT_OBJECT((&emit_stack[i]), obj->emitter); } emit_stack.clear(); obj->check_queue(); diff --git a/src/unix/write.cc b/src/unix/write.cc index 1931d1b..d136c9c 100644 --- a/src/unix/write.cc +++ b/src/unix/write.cc @@ -23,11 +23,8 @@ */ #include -NAN_METHOD(ttyu_js_c::js_write) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_write, { + THROW_IF_STOPPED(that); printf(TTYU_TOSTRING(args[1]), TTYU_TOSTRING(args[0])); refresh(); - NanReturnUndefined(); -} +}) diff --git a/src/win/colors.cc b/src/win/colors.cc index e132c75..debe87d 100644 --- a/src/win/colors.cc +++ b/src/win/colors.cc @@ -26,7 +26,6 @@ NAN_METHOD(ttyu_js_c::js_colors) { NanScope(); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); // TODO(@bbuecherl) NanReturnUndefined(); } diff --git a/src/win/cursor.cc b/src/win/cursor.cc new file mode 100644 index 0000000..a19ef41 --- /dev/null +++ b/src/win/cursor.cc @@ -0,0 +1,34 @@ +/* ttyutil - win/cursor.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +JSFUNCTION(ttyu_js_c, js_hide, { + THROW_IF_STOPPED(that); + // TODO(@bbuecherl) +}) + +JSFUNCTION(ttyu_js_c, js_show, { + THROW_IF_STOPPED(that); + // TODO(@bbuecherl) +}) diff --git a/src/win/stop.cc b/src/win/stop.cc index 1bc77d1..b05f5fb 100644 --- a/src/win/stop.cc +++ b/src/win/stop.cc @@ -27,11 +27,10 @@ NAN_METHOD(ttyu_js_c::js_stop) { NanScope(); DBG("::stop"); ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); - obj->running = FALSE; - obj->stop = TRUE; - - SetConsoleMode(obj->hin, obj->old_mode); - + if(obj->running) { + obj->running = FALSE; + obj->stop = TRUE; + SetConsoleMode(obj->hin, obj->old_mode); + } NanReturnUndefined(); } diff --git a/src/win/utils.cc b/src/win/utils.cc index 0187f72..267195f 100644 --- a/src/win/utils.cc +++ b/src/win/utils.cc @@ -38,10 +38,6 @@ bool ttyu_win_scr_update(ttyu_js_c *obj, bool initial) { obj->curx = con_info.dwCursorPosition.X; obj->cury = con_info.dwCursorPosition.Y - obj->top; - - /*if(initial) { - data->base_color = (short)con_info.wAttributes; - } */ return TRUE; } diff --git a/src/win/worker.cc b/src/win/worker.cc index 0aa7f87..80dc44a 100644 --- a/src/win/worker.cc +++ b/src/win/worker.cc @@ -27,138 +27,81 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, ttyu_js_c *obj) { DBG("::execute()"); DWORD readed; - INPUT_RECORD ir[WIN_BUFFER_SIZE]; DWORD i; - DBG(" start"); - /*if (obj->err) { - ttyu_event_t *event = - reinterpret_cast(malloc(sizeof(ttyu_event_t))); - ttyu_event_create_error(event); - progress.send(const_cast(event)); - if (obj->err) { - DBG(" killed"); - return FALSE; - } - obj->err->msg = NULL; - }*/ - - DBG(" read input"); + DWORD type; + INPUT_RECORD ir[WIN_BUFFER_SIZE]; ReadConsoleInput(obj->hin, ir, WIN_BUFFER_SIZE, &readed); - if (obj->stop) { DBG(" exited"); return FALSE; } // exit - + if (obj->stop) { return FALSE; } // exit for (i = 0; i < readed; ++i) { if (MOUSE_EVENT == ir[i].EventType) { - ttyu_event_t *event = - reinterpret_cast(malloc(sizeof(ttyu_event_t))); - ttyu_event_create_mouse(event, EVENT_ERROR, - static_cast(ir[i].Event.MouseEvent.dwButtonState), - static_cast(ir[i].Event.MouseEvent.dwMousePosition.X), - static_cast(ir[i].Event.MouseEvent.dwMousePosition.Y - obj->top), - ttyu_win_ctrl(ir[i].Event.MouseEvent.dwControlKeyState)); - - if (ir[i].Event.MouseEvent.dwButtonState == 0 && - ir[i].Event.MouseEvent.dwEventFlags == 0) { - event->type = EVENT_MOUSEUP; - } else if (ir[i].Event.MouseEvent.dwEventFlags == 0 || - ir[i].Event.MouseEvent.dwEventFlags == 2) { - event->type = EVENT_MOUSEDOWN; - } else if (ir[i].Event.MouseEvent.dwEventFlags == 1) { - event->type = EVENT_MOUSEMOVE; - } else if (ir[i].Event.MouseEvent.dwEventFlags == 4) { - event->type = EVENT_MOUSEWHEEL; - } else if (ir[i].Event.MouseEvent.dwEventFlags == 8) { - event->type = EVENT_MOUSEHWHEEL; - } - - progress.send(const_cast(event)); + type = MOUSE_EVENT; } else if (KEY_EVENT == ir[i].EventType && ir[i].Event.KeyEvent.bKeyDown) { - ttyu_event_t *event = - reinterpret_cast(malloc(sizeof(ttyu_event_t))); - char *ch = reinterpret_cast(malloc(sizeof(char) * 3)); - memcpy(ch, &(ir[i].Event.KeyEvent.uChar.UnicodeChar), sizeof(char) * 2); - ch[2] = '\0'; - - ttyu_event_create_key(event, ttyu_win_ctrl( - ir[i].Event.KeyEvent.dwControlKeyState), ch, - static_cast(ir[i].Event.KeyEvent.wVirtualKeyCode), - ttyu_win_which(ir[i].Event.KeyEvent.wVirtualKeyCode)); - - free(ch); - - DBG(" sending key"); - progress.send(const_cast(event)); + type = KEY_EVENT; } else if (WINDOW_BUFFER_SIZE_EVENT == ir[i].EventType) { - ttyu_event_t *event = - reinterpret_cast(malloc(sizeof(ttyu_event_t))); + type = WINDOW_BUFFER_SIZE_EVENT; + } else { + SDBG(" uncaught event %d", ir[i].EventType); + continue; + } + SDBG(" capturing event (type: %d)", type); + ttyu_event_t event; + switch (type) { + case MOUSE_EVENT: + ttyu_event_create_mouse(&event, EVENT_ERROR, + static_cast(ir[i].Event.MouseEvent.dwButtonState), + static_cast(ir[i].Event.MouseEvent.dwMousePosition.X), + static_cast(ir[i].Event.MouseEvent.dwMousePosition.Y-obj->top), + ttyu_win_ctrl(ir[i].Event.MouseEvent.dwControlKeyState)); - if (!ttyu_win_scr_update(obj, FALSE)) { - ttyu_event_create_error(event); - } else { - ttyu_event_create_resize(event); - } - progress.send(const_cast(event)); + if (ir[i].Event.MouseEvent.dwButtonState == 0 && + ir[i].Event.MouseEvent.dwEventFlags == 0) { + event.type = EVENT_MOUSEUP; + } else if (ir[i].Event.MouseEvent.dwEventFlags == 0 || + ir[i].Event.MouseEvent.dwEventFlags == 2) { + event.type = EVENT_MOUSEDOWN; + } else if (ir[i].Event.MouseEvent.dwEventFlags == 1) { + event.type = EVENT_MOUSEMOVE; + } else if (ir[i].Event.MouseEvent.dwEventFlags == 4) { + event.type = EVENT_MOUSEWHEEL; + } else if (ir[i].Event.MouseEvent.dwEventFlags == 8) { + event.type = EVENT_MOUSEHWHEEL; + } + break; + case KEY_EVENT: { + char ch[3]; + size_t ret = wcstombs(ch, &(ir[i].Event.KeyEvent.uChar.UnicodeChar), + sizeof(char) * 2); + ch[ret-1] = '\0'; + + ttyu_event_create_key(&event, + ttyu_win_ctrl(ir[i].Event.KeyEvent.dwControlKeyState), ch, + static_cast(ir[i].Event.KeyEvent.wVirtualKeyCode), + ttyu_win_which(ir[i].Event.KeyEvent.wVirtualKeyCode)); + free(ch); + } break; + default: // WINDOW_BUFFER_SIZE_EVENT + if (!ttyu_win_scr_update(obj, FALSE)) { + ttyu_event_create_error(&event); + } else { + ttyu_event_create_resize(&event); + } + break; } + + progress.send(const_cast(&event)); } - DBG(" end"); return TRUE; } void ttyu_worker_c::handle(ttyu_event_t *event) { - DBG("::handle()"); - v8::Local obj = NanNew(); - switch (event->type) { - case EVENT_RESIZE: - obj->Set(NanNew("type"), EVENTSTRING_RESIZE); - break; - case EVENT_KEY: - obj->Set(NanNew("type"), EVENTSTRING_KEY); - obj->Set(NanNew("ctrl"), - NanNew(event->key->ctrl)); - obj->Set(NanNew("char"), NanNew(event->key->c)); - obj->Set(NanNew("code"), - NanNew(event->key->code)); - obj->Set(NanNew("which"), - NanNew(event->key->which)); - break; - case EVENT_MOUSEDOWN: - case EVENT_MOUSEUP: - case EVENT_MOUSEMOVE: - case EVENT_MOUSEWHEEL: - case EVENT_MOUSEHWHEEL: - if (event->type == EVENT_MOUSEDOWN) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEDOWN); - } else if (event->type == EVENT_MOUSEUP) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEUP); - } else if (event->type == EVENT_MOUSEMOVE) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEMOVE); - } else if (event->type == EVENT_MOUSEWHEEL) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEWHEEL); - } else if (event->type == EVENT_MOUSEHWHEEL) { - obj->Set(NanNew("type"), EVENTSTRING_MOUSEHWHEEL); - } - obj->Set(NanNew("button"), - NanNew(event->mouse->button)); - obj->Set(NanNew("x"), NanNew(event->mouse->x)); - obj->Set(NanNew("y"), NanNew(event->mouse->y)); - obj->Set(NanNew("ctrl"), - NanNew(event->mouse->ctrl)); - break; - default: // EVENT_ERROR, EVENT_SIGNAL - obj->Set(NanNew("type"), EVENTSTRING_ERROR); - obj->Set(NanNew("error"), NanError("TODO")); - event->type = EVENT_ERROR; - break; - } - // TODO emit + NanScope(); + EMIT_EVENT_OBJECT(event, obj_->emitter); } void ttyu_worker_c::Execute() { - DBG("::Execute()"); ttyu_progress_c progress(this); - DBG(" barrier wait"); uv_barrier_wait(&obj_->barrier); - DBG(" start execute loop"); // loop execute until it returns false (error) while (execute(progress, obj_)) continue; } diff --git a/tests/index.js b/tests/index.js new file mode 100644 index 0000000..8af8288 --- /dev/null +++ b/tests/index.js @@ -0,0 +1 @@ +require("./key"); diff --git a/tools/build.js b/tools/build.js index b3f51c5..05199bb 100644 --- a/tools/build.js +++ b/tools/build.js @@ -32,7 +32,7 @@ for(var name in Const) { if(TTYU_CODE_DEBUG) { cont += "#define CDEBUG\n"; if(TTYU_CODE_DEBUG === "file") { - cont += "#define CDEBUG_FILE"; + cont += "#define CDEBUG_FILE\n"; } cont += "\n"; } From 4f25b2d084482588c94569dff06bd5954f775ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Wed, 1 Jul 2015 18:12:20 +0200 Subject: [PATCH 25/28] fix --- include/utils.h | 119 ++++++++++++++++++++++++++++++++++++++++++++++ src/unix/start.cc | 43 +++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 include/utils.h create mode 100644 src/unix/start.cc diff --git a/include/utils.h b/include/utils.h new file mode 100644 index 0000000..cc89f9d --- /dev/null +++ b/include/utils.h @@ -0,0 +1,119 @@ +/* ttyutil - utils.h - header file to define utility macros + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#ifndef INCLUDE_UTILS_H_ +#define INCLUDE_UTILS_H_ + +#define EXPORT_METHOD(tpl, name, cb) do { \ + v8::Local t = NanNew(cb); \ + tpl->InstanceTemplate()->Set(NanNew(name), \ + t->GetFunction(), v8::ReadOnly); \ +} while (0) + +#define TTYU_TOSTRING(handle) \ + (new v8::String::Utf8Value(handle->ToString()))->operator*() + +#define MUTEX_LOCK(mutex, action) do { \ + uv_mutex_lock(mutex); \ + action; \ + uv_mutex_unlock(mutex); \ +} while (0) + +#define JSFUNCTION(_0, ...) JSFUNCTION_(JSFUNCTION__STATIC(_0, __VA_ARGS__, 0),\ + JSFUNCTION__PROTO(_0, __VA_ARGS__, 0), __VA_ARGS__) +#define JSFUNCTION_(_2, _3, ...) JSFUNCTION__(__VA_ARGS__, _3, _2, 1, 0) +#define JSFUNCTION__(_1, _2, _3, ...) _3 +#define JSFUNCTION__STATIC(name, body, ...) NAN_METHOD(name) { \ + NanScope(); \ + if(1) body; \ + NanReturnUndefined(); \ +} +#define JSFUNCTION__PROTO(clas, name, body, ...) NAN_METHOD(clas::name) { \ + NanScope(); \ + clas *that = ObjectWrap::Unwrap(args.This()); \ + if(1) body; \ + NanReturnUndefined(); \ +} + +#define EMIT_EVENT_OBJECT(event, cb) do { \ + v8::Local __obj = NanNew(); \ + switch (event->type) { \ + case EVENT_RESIZE: \ + __obj->Set(NanNew("type"), EVENTSTRING_RESIZE); \ + break; \ + case EVENT_KEY: \ + __obj->Set(NanNew("type"), EVENTSTRING_KEY); \ + __obj->Set(NanNew("ctrl"), \ + NanNew(event->key->ctrl)); \ + __obj->Set(NanNew("char"), \ + NanNew(event->key->c)); \ + __obj->Set(NanNew("code"), \ + NanNew(event->key->code)); \ + __obj->Set(NanNew("which"), \ + NanNew(event->key->which)); \ + break; \ + case EVENT_MOUSEDOWN: \ + case EVENT_MOUSEUP: \ + case EVENT_MOUSEMOVE: \ + case EVENT_MOUSEWHEEL: \ + case EVENT_MOUSEHWHEEL: \ + if (event->type == EVENT_MOUSEDOWN) { \ + __obj->Set(NanNew("type"), EVENTSTRING_MOUSEDOWN); \ + } else if (event->type == EVENT_MOUSEUP) { \ + __obj->Set(NanNew("type"), EVENTSTRING_MOUSEUP); \ + } else if (event->type == EVENT_MOUSEMOVE) { \ + __obj->Set(NanNew("type"), EVENTSTRING_MOUSEMOVE); \ + } else if (event->type == EVENT_MOUSEWHEEL) { \ + __obj->Set(NanNew("type"), EVENTSTRING_MOUSEWHEEL); \ + } else if (event->type == EVENT_MOUSEHWHEEL) { \ + __obj->Set(NanNew("type"), EVENTSTRING_MOUSEHWHEEL); \ + } \ + __obj->Set(NanNew("button"), \ + NanNew(event->mouse->button)); \ + __obj->Set(NanNew("x"), \ + NanNew(event->mouse->x)); \ + __obj->Set(NanNew("y"), \ + NanNew(event->mouse->y)); \ + __obj->Set(NanNew("ctrl"), \ + NanNew(event->mouse->ctrl)); \ + break; \ + default: \ + __obj->Set(NanNew("type"), EVENTSTRING_ERROR); \ + __obj->Set(NanNew("error"), NanError("TODO")); \ + event->type = EVENT_ERROR; \ + break; \ + } \ + \ + v8::Local __args[] = { __obj }; \ + cb->Call(1, __args); \ +} while (0) + +#if defined(__GNUC__) && !(defined(DEBUG) && DEBUG) +# define TTYU_INLINE inline __attribute__((always_inline)) +#elif defined(_MSC_VER) && !(defined(DEBUG) && DEBUG) +# define TTYU_INLINE __forceinline +#else +# define TTYU_INLINE inline +#endif + +#endif // INCLUDE_UTILS_H_ diff --git a/src/unix/start.cc b/src/unix/start.cc new file mode 100644 index 0000000..fdc01c5 --- /dev/null +++ b/src/unix/start.cc @@ -0,0 +1,43 @@ +/* ttyutil - unix/start.cc + * https://github.com/clidejs/ttyutil + * + * Copyright Bernhard Bücherl + * + * 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. + */ +#include + +JSFUNCTION(ttyu_js_c, js_start, { + that->running = TRUE; + that->stop = FALSE; + that->worker_run = TRUE; + that->win = initscr(); + that->x = getcurx(that->win); + that->y = getcury(that->win); + + uv_barrier_init(&that->barrier, 3); + uv_mutex_init(&that->emitstacklock); + uv_mutex_init(&that->ungetlock); + uv_cond_init(&that->condition); + + uv_thread_create(&that->curses_thread, ttyu_js_c::curses_thread_func, that); + that->check_queue(); + + uv_barrier_wait(&that->barrier); +}) From e62675957f9ccb05008af68387f68ac2140d5ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Sun, 19 Jul 2015 19:12:43 +0200 Subject: [PATCH 26/28] fixed windows worker, fixed function macro for windows --- .travis.yml | 1 - appveyor.yml | 3 +-- include/utils.h | 26 ++++++++++++++++-------- include/win.h | 34 ++++++++++++++++++++++--------- lib/const.js | 3 ++- src/core/ttyu.cc | 17 +++++++--------- src/core/ttyu_event.cc | 8 ++++---- src/unix/beep.cc | 2 +- src/win/beep.cc | 9 +++------ src/win/clear.cc | 9 +++------ src/win/colors.cc | 9 +++------ src/win/emit.cc | 15 ++++++-------- src/win/goto.cc | 45 ++++++++++++++---------------------------- src/win/main.cc | 2 +- src/win/mode.cc | 5 ++--- src/win/resize.cc | 28 ++++++++++---------------- src/win/start.cc | 34 +++++++++++++++---------------- src/win/stop.cc | 30 ++++++++++++++++++---------- src/win/worker.cc | 11 +++++++---- src/win/write.cc | 7 ++----- 20 files changed, 146 insertions(+), 152 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9d76b96..0523752 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ os: - osx env: TTYU_NCURSES_REBUILD=true TTYU_BUILD_DEBUG=true node_js: - - "0.8" - "0.10" - "0.12" - "iojs-v2.2.0" diff --git a/appveyor.yml b/appveyor.yml index 4e2711c..fd6ffbf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,10 +4,9 @@ os: Windows Server 2012 R2 environment: matrix: # node.js - # - nodejs_version: "0.8" mocha does not work on windows with v0.8 - nodejs_version: "0.10" - nodejs_version: "0.12" - TTYU_NCURSES_REBUILD: true + TTYU_NCURSES_REBUILD: true # to make sure ncurses does not install TTYU_BUILD_DEBUG: true platform: diff --git a/include/utils.h b/include/utils.h index cc89f9d..127a59e 100644 --- a/include/utils.h +++ b/include/utils.h @@ -28,6 +28,7 @@ v8::Local t = NanNew(cb); \ tpl->InstanceTemplate()->Set(NanNew(name), \ t->GetFunction(), v8::ReadOnly); \ + ++_exports; \ } while (0) #define TTYU_TOSTRING(handle) \ @@ -39,19 +40,26 @@ uv_mutex_unlock(mutex); \ } while (0) -#define JSFUNCTION(_0, ...) JSFUNCTION_(JSFUNCTION__STATIC(_0, __VA_ARGS__, 0),\ - JSFUNCTION__PROTO(_0, __VA_ARGS__, 0), __VA_ARGS__) -#define JSFUNCTION_(_2, _3, ...) JSFUNCTION__(__VA_ARGS__, _3, _2, 1, 0) -#define JSFUNCTION__(_1, _2, _3, ...) _3 -#define JSFUNCTION__STATIC(name, body, ...) NAN_METHOD(name) { \ +#ifdef PLATFORM_WINDOWS +# define JSFUNCTION(_0, ...) JSFUNCTION__CALL(JSFUNCTION_((__VA_ARGS__, \ + JSFUNCTION_PROTO, JSFUNCTION_STATIC, 0)), (_0, __VA_ARGS__)) +# define JSFUNCTION__CALL(fun, args) fun args +# define JSFUNCTION_(args) JSFUNCTION__ args +# define JSFUNCTION__(_1, _2, _3, ...) _3 +#else +# define JSFUNCTION(_0, ...) JSFUNCTION_(__VA_ARGS__, JSFUNCTION_PROTO, \ + JSFUNCTION_STATIC, 0)(_0, __VA_ARGS__) +# define JSFUNCTION_(_1, _2, _3, ...) _3 +#endif +#define JSFUNCTION_STATIC(name, body) NAN_METHOD(name) { \ NanScope(); \ - if(1) body; \ + if(1) body \ NanReturnUndefined(); \ } -#define JSFUNCTION__PROTO(clas, name, body, ...) NAN_METHOD(clas::name) { \ +#define JSFUNCTION_PROTO(clas, name, body) NAN_METHOD(clas::name) { \ NanScope(); \ clas *that = ObjectWrap::Unwrap(args.This()); \ - if(1) body; \ + if(1) body \ NanReturnUndefined(); \ } @@ -105,7 +113,9 @@ } \ \ v8::Local __args[] = { __obj }; \ + DBG(" emit_event_object calling"); \ cb->Call(1, __args); \ + DBG(" emit_event_object called"); \ } while (0) #if defined(__GNUC__) && !(defined(DEBUG) && DEBUG) diff --git a/include/win.h b/include/win.h index 64f9b33..3c2ebda 100644 --- a/include/win.h +++ b/include/win.h @@ -40,7 +40,8 @@ class ttyu_worker_c : public NanAsyncWorker { friend class ttyu_worker_c; public: void send(const ttyu_event_t *event) const { - that_->send_(event); + DBG("::send"); + that_->send_(event); } private: explicit ttyu_progress_c(ttyu_worker_c *that) : that_(that) {} @@ -63,22 +64,31 @@ class ttyu_worker_c : public NanAsyncWorker { async->data = this; } ~ttyu_worker_c() { + DBG("::~ttyu_worker_c"); uv_mutex_destroy(async_lock); ttyu_event_destroy(asyncdata_); - free(asyncdata_); + if(asyncdata_) + free(asyncdata_); + DBG("::~ttyu_worker_c freed"); } void progress() { + DBG("::process aquire lock"); uv_mutex_lock(async_lock); + DBG("::process aquired lock"); ttyu_event_t *event = asyncdata_; asyncdata_ = NULL; uv_mutex_unlock(async_lock); + DBG("::process released lock"); if (event) { handle(event); + DBG("destroying event"); + ttyu_event_destroy(event); + DBG("freeing event"); + free(event); + DBG("freed event"); } - ttyu_event_destroy(event); - free(event); } bool execute(const ttyu_progress_c& progress, ttyu_js_c *obj); @@ -94,16 +104,22 @@ class ttyu_worker_c : public NanAsyncWorker { private: void send_(const ttyu_event_t *event) { - ttyu_event_t *new_event = - reinterpret_cast(malloc(sizeof(event))); - memcpy(&new_event, &event, sizeof(event)); + DBG("::send_"); + size_t size = sizeof(*event); + ttyu_event_t *new_event = reinterpret_cast(malloc(size)); + memcpy(new_event, event, size); + DBG("::send_ aquire lock"); uv_mutex_lock(async_lock); + DBG("::send_ aquired lock"); ttyu_event_t *old_event = asyncdata_; asyncdata_ = new_event; uv_mutex_unlock(async_lock); + DBG("::send_ released lock"); ttyu_event_destroy(old_event); - free(old_event); + if(old_event != NULL) + free(old_event); + DBG(" uv_async_send"); uv_async_send(async); } @@ -134,7 +150,7 @@ class ttyu_worker_c : public NanAsyncWorker { DWORD cury; \ uv_mutex_t emitlock; \ uv_barrier_t barrier; \ - ttyu_worker_c worker + ttyu_worker_c *worker bool ttyu_win_scr_update(ttyu_js_c *obj, bool initial); int ttyu_win_which(DWORD code); diff --git a/lib/const.js b/lib/const.js index 7b116a8..f69682a 100644 --- a/lib/const.js +++ b/lib/const.js @@ -213,7 +213,8 @@ module.exports = { ZOOM: 0xFB, NONAME: 0xFC, PA1: 0xFD, - OEM_CLEAR: 0xFE + OEM_CLEAR: 0xFE, + FN: 0xFF }, Ctrl: { diff --git a/src/core/ttyu.cc b/src/core/ttyu.cc index c8a1ff8..22c7334 100644 --- a/src/core/ttyu.cc +++ b/src/core/ttyu.cc @@ -23,28 +23,24 @@ */ #include -NAN_METHOD(ttyu_js_c::js_new) { - NanScope(); +JSFUNCTION(ttyu_js_c::js_new, { ttyu_js_c *obj = new ttyu_js_c(); obj->Wrap(args.This()); obj->emitter = new NanCallback(v8::Local::Cast(args[0])); NanReturnThis(); -} +}) -NAN_METHOD(ttyu_js_c::js_running) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - NanReturnValue(obj->running ? NanTrue() : NanFalse()); -} +JSFUNCTION(ttyu_js_c, js_running, { + NanReturnValue(that->running ? NanTrue() : NanFalse()); +}) // initialize node module void ttyu_js_c::init(v8::Handle exports, v8::Handle module) { - + int _exports = 0; v8::Local tpl = NanNew(js_new); tpl->SetClassName(NanNew("ttyu_js_c")); - tpl->InstanceTemplate()->SetInternalFieldCount(9); EXPORT_METHOD(tpl, "start", js_start); EXPORT_METHOD(tpl, "stop", js_stop); @@ -68,6 +64,7 @@ void ttyu_js_c::init(v8::Handle exports, EXPORT_METHOD(tpl, "hide", js_hide); EXPORT_METHOD(tpl, "show", js_show); + tpl->InstanceTemplate()->SetInternalFieldCount(_exports); module->Set(NanNew("exports"), tpl->GetFunction()); } NODE_MODULE(ttyu, ttyu_js_c::init); diff --git a/src/core/ttyu_event.cc b/src/core/ttyu_event.cc index d8adf31..333d2ab 100644 --- a/src/core/ttyu_event.cc +++ b/src/core/ttyu_event.cc @@ -37,10 +37,10 @@ void ttyu_event_create_resize(ttyu_event_t *event) { void ttyu_event_create_key(ttyu_event_t *event, int ctrl, char *c, int code, int which) { - char *ch = - reinterpret_cast(std::malloc(sizeof(char) * (strlen(c) + 1))); - memcpy(ch, c, sizeof(char) * strlen(c)); - ch[strlen(c)] = '\0'; + size_t len = strlen(c); + char *ch = reinterpret_cast(std::malloc(sizeof(char) * (len + 1))); + memcpy(ch, c, sizeof(char) * len); + ch[len] = '\0'; event->type = EVENT_KEY; event->key = reinterpret_cast(std::malloc(sizeof(ttyu_key_t))); diff --git a/src/unix/beep.cc b/src/unix/beep.cc index 1e23e41..e0b577c 100644 --- a/src/unix/beep.cc +++ b/src/unix/beep.cc @@ -23,7 +23,7 @@ */ #include -JSFUNCTION(ttyu_js_c,js_beep, { +JSFUNCTION(ttyu_js_c, js_beep, { THROW_IF_STOPPED(that); beep(); }) diff --git a/src/win/beep.cc b/src/win/beep.cc index 8b3a9c8..1e86c8b 100644 --- a/src/win/beep.cc +++ b/src/win/beep.cc @@ -23,10 +23,7 @@ */ #include -NAN_METHOD(ttyu_js_c::js_beep) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_beep, { + THROW_IF_STOPPED(that); // TODO(@bbuecherl) - NanReturnUndefined(); -} +}) diff --git a/src/win/clear.cc b/src/win/clear.cc index 737aee9..cf6a7fd 100644 --- a/src/win/clear.cc +++ b/src/win/clear.cc @@ -23,10 +23,7 @@ */ #include -NAN_METHOD(ttyu_js_c::js_clear) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_clear, { + THROW_IF_STOPPED(that); // TODO(@bbuecherl) - NanReturnUndefined(); -} +}) diff --git a/src/win/colors.cc b/src/win/colors.cc index debe87d..10e7a47 100644 --- a/src/win/colors.cc +++ b/src/win/colors.cc @@ -23,9 +23,6 @@ */ #include -NAN_METHOD(ttyu_js_c::js_colors) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - // TODO(@bbuecherl) - NanReturnUndefined(); -} +JSFUNCTION(ttyu_js_c::js_colors, { + NanReturnValue(NanNew(16)); +}) diff --git a/src/win/emit.cc b/src/win/emit.cc index f5b4ace..042e867 100644 --- a/src/win/emit.cc +++ b/src/win/emit.cc @@ -23,12 +23,10 @@ */ #include -NAN_METHOD(ttyu_js_c::js_emit) { - NanScope(); +JSFUNCTION(ttyu_js_c, js_emit, { DBG("::js_emit"); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); - if (obj->running) { + THROW_IF_STOPPED(that); + if (that->running) { int ev = args[0]->Int32Value(); INPUT_RECORD in[1]; DWORD w; @@ -72,7 +70,7 @@ NAN_METHOD(ttyu_js_c::js_emit) { in[0].EventType = MOUSE_EVENT; pos.X = static_cast(args[2]->Int32Value()); - pos.Y = static_cast(args[3]->Int32Value() + obj->top); + pos.Y = static_cast(args[3]->Int32Value() + that->top); mev.dwControlKeyState = ttyu_win_state(args[4]->Int32Value()); if (ev == EVENT_MOUSEUP) { @@ -101,8 +99,7 @@ NAN_METHOD(ttyu_js_c::js_emit) { } if (in[0].EventType != 0) { - WriteConsoleInput(obj->hin, in, 1, &w); + WriteConsoleInput(that->hin, in, 1, &w); } } - NanReturnUndefined(); -} +}) diff --git a/src/win/goto.cc b/src/win/goto.cc index bc36849..007c580 100644 --- a/src/win/goto.cc +++ b/src/win/goto.cc @@ -23,42 +23,27 @@ */ #include -NAN_METHOD(ttyu_js_c::js_setx) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_setx, { + THROW_IF_STOPPED(that); // TODO(@bbuecherl) - NanReturnUndefined(); -} +}) -NAN_METHOD(ttyu_js_c::js_getx) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_getx, { + THROW_IF_STOPPED(that); // TODO(@bbuecherl) - NanReturnUndefined(); -} +}) -NAN_METHOD(ttyu_js_c::js_sety) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_sety, { + THROW_IF_STOPPED(that); // TODO(@bbuecherl) - NanReturnUndefined(); -} +}) -NAN_METHOD(ttyu_js_c::js_gety) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_gety, { + THROW_IF_STOPPED(that); // TODO(@bbuecherl) - NanReturnUndefined(); -} +}) -NAN_METHOD(ttyu_js_c::js_goto) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - THROW_IF_STOPPED(obj); +JSFUNCTION(ttyu_js_c, js_goto, { + THROW_IF_STOPPED(that); // TODO(@bbuecherl) - NanReturnUndefined(); -} +}) diff --git a/src/win/main.cc b/src/win/main.cc index 659715e..c2f3247 100644 --- a/src/win/main.cc +++ b/src/win/main.cc @@ -23,7 +23,7 @@ */ #include -ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), worker(this), top(0) { +ttyu_js_c::ttyu_js_c() : running(FALSE), stop(TRUE), top(0) { DBG("::ttyu_js_c"); } diff --git a/src/win/mode.cc b/src/win/mode.cc index c42889f..0af31f4 100644 --- a/src/win/mode.cc +++ b/src/win/mode.cc @@ -23,7 +23,6 @@ */ #include -NAN_METHOD(ttyu_js_c::js_mode) { - NanScope(); +JSFUNCTION(ttyu_js_c::js_mode, { NanReturnValue(NanNew(MODE_CMD)); -} +}) diff --git a/src/win/resize.cc b/src/win/resize.cc index 2992000..6dd4d8b 100644 --- a/src/win/resize.cc +++ b/src/win/resize.cc @@ -23,32 +23,24 @@ */ #include -NAN_METHOD(ttyu_js_c::js_getwidth) { - NanScope(); +JSFUNCTION(ttyu_js_c, js_getwidth, { // TODO(@bbuecherl) NanReturnValue(NanNew(0)); -} +}) -NAN_METHOD(ttyu_js_c::js_getheight) { - NanScope(); +JSFUNCTION(ttyu_js_c, js_getheight, { // TODO(@bbuecherl) NanReturnValue(NanNew(0)); -} +}) -NAN_METHOD(ttyu_js_c::js_setwidth) { - NanScope(); +JSFUNCTION(ttyu_js_c, js_setwidth, { // TODO(@bbuecherl) - NanReturnUndefined(); -} +}) -NAN_METHOD(ttyu_js_c::js_setheight) { - NanScope(); +JSFUNCTION(ttyu_js_c, js_setheight, { // TODO(@bbuecherl) - NanReturnUndefined(); -} +}) -NAN_METHOD(ttyu_js_c::js_resize) { - NanScope(); +JSFUNCTION(ttyu_js_c, js_resize, { // TODO(@bbuecherl) - NanReturnUndefined(); -} +}) diff --git a/src/win/start.cc b/src/win/start.cc index 1a4f0aa..091da0e 100644 --- a/src/win/start.cc +++ b/src/win/start.cc @@ -23,36 +23,34 @@ */ #include -NAN_METHOD(ttyu_js_c::js_start) { - NanScope(); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - obj->running = TRUE; - obj->stop = FALSE; +JSFUNCTION(ttyu_js_c, js_start, { + that->running = TRUE; + that->stop = FALSE; DBG("::js_start()"); - uv_mutex_init(&obj->emitlock); - uv_barrier_init(&obj->barrier, 2); + uv_mutex_init(&that->emitlock); + uv_barrier_init(&that->barrier, 2); - obj->hin = GetStdHandle(STD_INPUT_HANDLE); - obj->hout = GetStdHandle(STD_OUTPUT_HANDLE); + that->hin = GetStdHandle(STD_INPUT_HANDLE); + that->hout = GetStdHandle(STD_OUTPUT_HANDLE); - if (INVALID_HANDLE_VALUE == obj->hin || INVALID_HANDLE_VALUE == obj->hout) { + if (INVALID_HANDLE_VALUE == that->hin || INVALID_HANDLE_VALUE == that->hout) { NanThrowError("invalid std handles"); } - GetConsoleMode(obj->hin, &(obj->old_mode)); - DWORD new_mode = ((obj->old_mode | ENABLE_MOUSE_INPUT | + GetConsoleMode(that->hin, &(that->old_mode)); + DWORD new_mode = ((that->old_mode | ENABLE_MOUSE_INPUT | ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT | ENABLE_WINDOW_INPUT) & ~(ENABLE_QUICK_EDIT_MODE)); - SetConsoleMode(obj->hin, new_mode); + that->worker = new ttyu_worker_c(that); + SetConsoleMode(that->hin, new_mode); DBG(" async queue start"); - NanAsyncQueueWorker(&obj->worker); + NanAsyncQueueWorker(that->worker); DBG(" wait barrier"); - uv_barrier_wait(&obj->barrier); + uv_barrier_wait(&that->barrier); DBG(" destroy barrier"); - uv_barrier_destroy(&obj->barrier); + uv_barrier_destroy(&that->barrier); DBG(" destroyed barrier"); - NanReturnUndefined(); -} +}) diff --git a/src/win/stop.cc b/src/win/stop.cc index b05f5fb..c592b16 100644 --- a/src/win/stop.cc +++ b/src/win/stop.cc @@ -23,14 +23,24 @@ */ #include -NAN_METHOD(ttyu_js_c::js_stop) { - NanScope(); - DBG("::stop"); - ttyu_js_c *obj = ObjectWrap::Unwrap(args.This()); - if(obj->running) { - obj->running = FALSE; - obj->stop = TRUE; - SetConsoleMode(obj->hin, obj->old_mode); +JSFUNCTION(ttyu_js_c, js_stop, { + if(that->running) { + DBG("::stop stopping"); + INPUT_RECORD in[1]; + KEY_EVENT_RECORD kev; + DWORD w; + + kev.bKeyDown = TRUE; + kev.wVirtualKeyCode = WHICH_FN; + kev.dwControlKeyState = 0; + kev.wRepeatCount = 1; + kev.wVirtualScanCode = MapVirtualKey(WHICH_FN, MAPVK_VK_TO_VSC); + in[0].EventType = KEY_EVENT; + in[0].Event.KeyEvent = kev; + + that->running = FALSE; + that->stop = TRUE; + WriteConsoleInput(that->hin, in, 1, &w); + SetConsoleMode(that->hin, that->old_mode); } - NanReturnUndefined(); -} +}) diff --git a/src/win/worker.cc b/src/win/worker.cc index 80dc44a..6ce6258 100644 --- a/src/win/worker.cc +++ b/src/win/worker.cc @@ -69,10 +69,10 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, } break; case KEY_EVENT: { - char ch[3]; - size_t ret = wcstombs(ch, &(ir[i].Event.KeyEvent.uChar.UnicodeChar), - sizeof(char) * 2); - ch[ret-1] = '\0'; + char *ch = reinterpret_cast(std::malloc(sizeof(char) * 3)); + wcstombs(ch, &(ir[i].Event.KeyEvent.uChar.UnicodeChar), + sizeof(char) * 2); + ch[2] = '\0'; ttyu_event_create_key(&event, ttyu_win_ctrl(ir[i].Event.KeyEvent.dwControlKeyState), ch, @@ -89,6 +89,7 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, break; } + DBG(" emitting"); progress.send(const_cast(&event)); } return TRUE; @@ -96,7 +97,9 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, void ttyu_worker_c::handle(ttyu_event_t *event) { NanScope(); + DBG("::handle"); EMIT_EVENT_OBJECT(event, obj_->emitter); + DBG(" handled"); } void ttyu_worker_c::Execute() { diff --git a/src/win/write.cc b/src/win/write.cc index aed0fdc..021a1bc 100644 --- a/src/win/write.cc +++ b/src/win/write.cc @@ -23,9 +23,6 @@ */ #include -NAN_METHOD(ttyu_js_c::js_write) { - NanScope(); - DBG("::write"); +JSFUNCTION(ttyu_js_c::js_write, { printf("%s", TTYU_TOSTRING(args[0])); - NanReturnUndefined(); -} +}) From f37faa7f2f7ae8f28ccf18ccdee3b3548a69e8ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Tue, 21 Jul 2015 01:13:46 +0200 Subject: [PATCH 27/28] improved installation process --- .gitmodules | 3 -- .travis.yml | 2 +- binding.gyp | 6 +-- deps/.gitkeep | 0 deps/ncurses | 1 - include/ttyu.h | 3 +- include/utils.h | 11 ++--- installer/generate.js | 47 +++++++++++++++++++ installer/index.js | 28 ++++++++++++ installer/ncurses/build.js | 28 ++++++++++++ installer/ncurses/download.js | 17 +++++++ installer/ncurses/index.js | 45 +++++++++++++++++++ installer/util.js | 49 ++++++++++++++++++++ package.json | 1 + src/core/ttyu.cc | 3 +- tests/key.js | 4 +- tools/build.js | 85 ----------------------------------- 17 files changed, 229 insertions(+), 104 deletions(-) delete mode 100644 .gitmodules create mode 100644 deps/.gitkeep delete mode 160000 deps/ncurses create mode 100644 installer/generate.js create mode 100644 installer/index.js create mode 100644 installer/ncurses/build.js create mode 100644 installer/ncurses/download.js create mode 100644 installer/ncurses/index.js create mode 100644 installer/util.js delete mode 100644 tools/build.js diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 57032ee..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "deps/ncurses"] - path = deps/ncurses - url = git://ncurses.scripts.mit.edu/ncurses.git diff --git a/.travis.yml b/.travis.yml index 0523752..e1d2128 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: node_js os: - linux - osx -env: TTYU_NCURSES_REBUILD=true TTYU_BUILD_DEBUG=true +env: TTYU_NCURSES_REBUILD=true TTYU_BUILD_DEBUG=true TTYU_CODE_DEBUG=true node_js: - "0.10" - "0.12" diff --git a/binding.gyp b/binding.gyp index 1d57cd2..040bc09 100644 --- a/binding.gyp +++ b/binding.gyp @@ -15,9 +15,9 @@ "actions": [ { "action_name": "preinstall", - "inputs": [ "tools/build.js" ], + "inputs": [ "lib/const.js" ], "outputs": [ "include/generated.h" ], - "action": [ "node", "tools/build.js" ] + "action": [ "node", "installer/index.js" ] } ], @@ -45,7 +45,7 @@ }, { # "OS!='win" "include_dirs": [ "../deps/ncurses" ], "link_settings": { - "libraries": [ "-lncurses++", "-lncurses" ], + "libraries": [ "-lncurses" ], "library_dirs": [ "../deps/ncurses/lib/" ] }, "sources": [ diff --git a/deps/.gitkeep b/deps/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/deps/ncurses b/deps/ncurses deleted file mode 160000 index fe7c48d..0000000 --- a/deps/ncurses +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fe7c48d7d5115212f09b4ec0d84b189a76953f0d diff --git a/include/ttyu.h b/include/ttyu.h index 68f2cc5..9e56815 100644 --- a/include/ttyu.h +++ b/include/ttyu.h @@ -117,8 +117,7 @@ class ttyu_js_c : public node::ObjectWrap { ttyu_js_c(); ~ttyu_js_c(); - static void init(v8::Handle exports, - v8::Handle module); + static void init(DATATYPE exports, DATATYPE module); static NAN_METHOD(js_new); static NAN_METHOD(js_start); static NAN_METHOD(js_stop); diff --git a/include/utils.h b/include/utils.h index 127a59e..0b13d9c 100644 --- a/include/utils.h +++ b/include/utils.h @@ -24,6 +24,8 @@ #ifndef INCLUDE_UTILS_H_ #define INCLUDE_UTILS_H_ +#define DATATYPE v8::Local + #define EXPORT_METHOD(tpl, name, cb) do { \ v8::Local t = NanNew(cb); \ tpl->InstanceTemplate()->Set(NanNew(name), \ @@ -41,16 +43,15 @@ } while (0) #ifdef PLATFORM_WINDOWS -# define JSFUNCTION(_0, ...) JSFUNCTION__CALL(JSFUNCTION_((__VA_ARGS__, \ +# define JSFUNCTION(_0, ...) JSFUNCTION_CALL(JSFUNCTION_((__VA_ARGS__, \ JSFUNCTION_PROTO, JSFUNCTION_STATIC, 0)), (_0, __VA_ARGS__)) -# define JSFUNCTION__CALL(fun, args) fun args +# define JSFUNCTION_CALL(fun, args) fun args # define JSFUNCTION_(args) JSFUNCTION__ args -# define JSFUNCTION__(_1, _2, _3, ...) _3 #else -# define JSFUNCTION(_0, ...) JSFUNCTION_(__VA_ARGS__, JSFUNCTION_PROTO, \ +# define JSFUNCTION(_0, ...) JSFUNCTION__(__VA_ARGS__, JSFUNCTION_PROTO, \ JSFUNCTION_STATIC, 0)(_0, __VA_ARGS__) -# define JSFUNCTION_(_1, _2, _3, ...) _3 #endif +#define JSFUNCTION__(_1, _2, _3, ...) _3 #define JSFUNCTION_STATIC(name, body) NAN_METHOD(name) { \ NanScope(); \ if(1) body \ diff --git a/installer/generate.js b/installer/generate.js new file mode 100644 index 0000000..3629d64 --- /dev/null +++ b/installer/generate.js @@ -0,0 +1,47 @@ +var path = require("path"); +var fs = require("fs"); + +module.exports = function(ENV) { + return function(cb) { + var generated = path.join(__dirname, "..", "include", "generated.h"); + var cont = "/** ttyutil - generated.h - generated header\n" + + " * https://github.com/clidejs/ttyutil\n" + + " *\n" + + " * Copyright Bernhard Bücherl \n" + + " *\n" + + " * do not change this file,\n" + + " * it is autogenerated by 'npm install',\n" + + " * these constants are set in /const.js\n" + + " */\n" + + "#ifndef INCLUDE_GENERATED_H_\n" + + "#define INCLUDE_GENERATED_H_\n" + + "\n"; + for(var name in ENV.CONST) { + for(var sub in ENV.CONST[name]) { + cont += "#define " + name.toUpperCase() + "_" + sub.toUpperCase() + + " " + toCpp(ENV.CONST[name][sub]) + "\n"; + } + cont += "\n"; + } + if(ENV.TTYU_CODE_DEBUG) { + cont += "#define CDEBUG\n"; + if(ENV.TTYU_CODE_DEBUG === "file") { + cont += "#define CDEBUG_FILE\n"; + } + cont += "\n"; + } + cont += "#endif // INCLUDE_GENERATED_H_\n"; + console.log(" [preinstall] write constants to 'generated.h'"); + fs.writeFile(generated, cont, function(err) { + cb(err, 1); + }); + } +}; + +function toCpp(v) { + if(typeof v === "string") { + return "NanNew(\"" + v + "\")"; + } else { + return v; + } +} diff --git a/installer/index.js b/installer/index.js new file mode 100644 index 0000000..d81b147 --- /dev/null +++ b/installer/index.js @@ -0,0 +1,28 @@ +var util = require("./util"); + +var ENV = { + TTYU_NCURSES_REBUILD: process.env.TTYU_NCURSES_REBUILD || false, + TTYU_BUILD_DEBUG: process.env.TTYU_BUILD_DEBUG || false, + TTYU_CODE_DEBUG: process.env.TTYU_CODE_DEBUG || false, + WIN_OS: process.platform === "win32", + PKG: require("../package.json"), + CONST: require("../lib/const") +}; + +util.waterfall([ + // startup + function(cb) { + console.log(" [preinstall] ENV: [ TTYU_NCURSES_REBUILD='" + + ENV.TTYU_NCURSES_REBUILD + "', TTYU_BUILD_DEBUG='" + + ENV.TTYU_BUILD_DEBUG + "', TTYU_CODE_DEBUG='" + ENV.TTYU_CODE_DEBUG + + "', WIN_OS='" + ENV.WIN_OS + "' ]"); + cb(); + }, + // generate header file + require("./generate")(ENV), + // prepare ncurses + require("./ncurses")(ENV) +], function(err) { + if(err) throw err; + console.log(" [preinstall] finished with code -0"); +}); diff --git a/installer/ncurses/build.js b/installer/ncurses/build.js new file mode 100644 index 0000000..eda3571 --- /dev/null +++ b/installer/ncurses/build.js @@ -0,0 +1,28 @@ +var cp = require("child_process"); + +module.exports = function(ENV, cb) { + console.log(" [preinstall/ncurses] './configure'"); + var cfg = cp.spawn("./configure", ["--with-shared", "--enable-pc-files", + "--enable-widec", "--without-normal"], { + cwd: ENV.NCURSES_PATH + }); + if(ENV.TTYU_BUILD_DEBUG) { + cfg.stdout.pipe(process.stdout); + cfg.stderr.pipe(process.stderr); + } + cfg.on("exit", function(code) { + if(code !== 0) throw "ncurses './configure' exited with code -" + code; + console.log(" [preinstall/ncurses] 'make'"); + var make = cp.spawn("make", { + cwd: ENV.NCURSES_PATH + }); + if(ENV.TTYU_BUILD_DEBUG) { + make.stdout.pipe(process.stdout); + make.stderr.pipe(process.stderr); + } + make.on("exit", function(code) { + if(code !== 0) throw "ncurses 'make' exited with code -" + code; + cb(); + }); + }); +}; diff --git a/installer/ncurses/download.js b/installer/ncurses/download.js new file mode 100644 index 0000000..483cd4f --- /dev/null +++ b/installer/ncurses/download.js @@ -0,0 +1,17 @@ +var gethub = require("gethub"); + +var build = require("./build"); +var util = require("../util"); + +module.exports = function(ENV, download, cb) { + if(download) { + util.rmDirRFSync(ENV.NCURSES_PATH); + console.log(" [preinstall/ncurses] cloning from " + ENV.NCURSES_URL); + gethub("mirror", "ncurses", "master", ENV.NCURSES_PATH, function(err) { + if(err) throw err; + build(ENV, cb); + }); + } else { + build(ENV, cb); + } +}; diff --git a/installer/ncurses/index.js b/installer/ncurses/index.js new file mode 100644 index 0000000..863adfe --- /dev/null +++ b/installer/ncurses/index.js @@ -0,0 +1,45 @@ +var cp = require("child_process"); +var fs = require("fs"); +var path = require("path"); +var https = require("https"); + +var util = require("../util"); +var execute = require("./download"); + +module.exports = function(ENV) { + ENV.NCURSES_PATH = path.join(__dirname, "..", "..", "deps", "ncurses"); + ENV.NCURSES_URL = "https://github.com/mirror/ncurses"; + var rebuild = function(cb) { + console.log(" [preinstall/ncurses] rebuilding..."); + cb(); + }; + + return function(cb) { + if(ENV.WIN_OS) { + console.log(" [preinstall/ncurses] step skipped for windows"); + cb(); + } else { + console.log(" [preinstall/ncurses] checking..."); + var rebuild = ENV.TTYU_NCURSES_REBUILD; + var download = !fs.existsSync(ENV.NCURSES_PATH); + + if(rebuild) return execute(ENV, true, cb); + + util.spawn("gcc", ["-lncurses"], { }, + function(code, stdout, stderr) { + if(stderr.search(/\-lncurses/) === -1) { + console.log(" [preinstall/ncurses] library found"); + cb(); + } else { + if(fs.existsSync(path.join(ENV.NCURSES_PATH, "lib", + "libncurses++.a"))) { + console.log(" [preinstall/ncurses] using latest private build"); + cb(); + } else { + execute(ENV, download, cb); + } + } + }); + } + } +}; diff --git a/installer/util.js b/installer/util.js new file mode 100644 index 0000000..06932dc --- /dev/null +++ b/installer/util.js @@ -0,0 +1,49 @@ +var path = require("path"); +var fs = require("fs"); +var cp = require("child_process"); + +var util = module.exports = { + // waterfall function (inspired by async.waterfall) + waterfall: function(fns, end) { + (function h2o(index) { + fns[index](function(err, id) { + if(err) return end(err, id); + if(++index < fns.length) h2o(index); else end(); + }); + })(0); + }, + + // spawn a new process (child_process.spawn) which will callback when finished + // with stdout and stderr output as string + spawn: function(cmd, args, options, cb) { + var proc = cp.spawn(cmd, args, options); + var stdout = ""; + var stderr = ""; + + proc.stdout.on("data", function(chunk) { + stdout += chunk; + }); + proc.stderr.on("data", function(chunk) { + stderr += chunk; + }); + proc.on("close", function(code) { + cb(code, stdout, stderr); + }); + }, + + rmDirRFSync: function(p) { + var files = []; + if( fs.existsSync(p) ) { + files = fs.readdirSync(p); + for(var index = 0, file; index < files.length; ++index) { + file = path.join(p, files[index]); + if(fs.lstatSync(file).isDirectory()) { // recurse + util.rmDirRFSync(file); + } else { // delete file + fs.unlinkSync(file); + } + } + fs.rmdirSync(p); + } + } +}; diff --git a/package.json b/package.json index 5e6fa8c..66d539b 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ }, "homepage": "https://github.com/clidejs/ttyutil", "dependencies": { + "gethub": "^2.0.1", "nan": "1.8.4" }, "engines": { diff --git a/src/core/ttyu.cc b/src/core/ttyu.cc index 22c7334..67d12f2 100644 --- a/src/core/ttyu.cc +++ b/src/core/ttyu.cc @@ -35,8 +35,7 @@ JSFUNCTION(ttyu_js_c, js_running, { }) // initialize node module -void ttyu_js_c::init(v8::Handle exports, - v8::Handle module) { +void ttyu_js_c::init(DATATYPE exports, DATATYPE module){ int _exports = 0; v8::Local tpl = NanNew(js_new); diff --git a/tests/key.js b/tests/key.js index d0a9040..8683d1b 100644 --- a/tests/key.js +++ b/tests/key.js @@ -82,7 +82,7 @@ var unix_required = [ ttyu.WHICH.F24, ttyu.WHICH.BROWSER_REFRESH ]; -console.log("\r\n[tests/key]\r"); +console.log("\r\ntest 'tests/key.js'\r"); ttyu.start(); (function check(i, cb) { @@ -96,5 +96,5 @@ ttyu.start(); ttyu.emit(ttyu.KeyEvent(unix_required[i], 0)); })(unix_required.length - 1, function() { ttyu.stop(); - console.log("[tests/key] passed\r"); + console.log("test 'tests/key.js' passed\r"); }); diff --git a/tools/build.js b/tools/build.js deleted file mode 100644 index 05199bb..0000000 --- a/tools/build.js +++ /dev/null @@ -1,85 +0,0 @@ -var fs = require("fs"); -var path = require("path"); -var cp = require("child_process"); - -var Const = require("../lib/const"); -var pkg = require("../package.json"); - -var generated = path.join(__dirname, "..", "include", "generated.h"); -var cont = "/** ttyutil - generated.h - generated header\n" + - " * https://github.com/clidejs/ttyutil\n" + - " *\n" + - " * Copyright Bernhard Bücherl \n" + - " *\n" + - " * do not change this file,\n" + - " * it is autogenerated by 'npm install',\n" + - " * these constants are set in /const.js\n" + - " */\n" + - "#ifndef INCLUDE_GENERATED_H_\n" + - "#define INCLUDE_GENERATED_H_\n" + - "\n"; -var TTYU_NCURSES_REBUILD = process.env.TTYU_NCURSES_REBUILD || false; -var TTYU_BUILD_DEBUG = process.env.TTYU_BUILD_DEBUG || false; -var TTYU_CODE_DEBUG = process.env.TTYU_CODE_DEBUG || false; - -for(var name in Const) { - for(var sub in Const[name]) { - cont += "#define " + name.toUpperCase() + "_" + sub.toUpperCase() + - " " + toCpp(Const[name][sub]) + "\n"; - } - cont += "\n"; -} -if(TTYU_CODE_DEBUG) { - cont += "#define CDEBUG\n"; - if(TTYU_CODE_DEBUG === "file") { - cont += "#define CDEBUG_FILE\n"; - } - cont += "\n"; -} -cont += "#endif // INCLUDE_GENERATED_H_\n"; - -function toCpp(v) { - if(typeof v === "string") { - return "NanNew(\"" + v + "\")"; - } else { - return v; - } -} - -console.log(" [preinstall] ENV: [ TTYU_NCURSES_REBUILD='" + - TTYU_NCURSES_REBUILD + "', TTYU_BUILD_DEBUG='" + TTYU_BUILD_DEBUG + - "', TTYU_CODE_DEBUG='" + TTYU_CODE_DEBUG + "' ]"); -console.log(" [preinstall] write constants to 'generated.h'"); -fs.writeFile(generated, cont, function(err) { - if(err) throw err; - if((!fs.existsSync(path.join(__dirname, "..", "deps", "ncurses", "lib", - "libncurses++.a")) || TTYU_NCURSES_REBUILD) && - process.platform !== "win32") { - console.log(" [preinstall] ncurses './configure'"); - var cfg = cp.spawn("./configure", ["--with-shared", "--enable-pc-files", - "--enable-widec", "--without-normal"], { - cwd: path.join(__dirname, "..", "deps", "ncurses") - }); - if(TTYU_BUILD_DEBUG) { - cfg.stdout.pipe(process.stdout); - cfg.stderr.pipe(process.stderr); - } - cfg.on("exit", function(code) { - if(code !== 0) throw "ncurses './configure' exited with code -" + code; - console.log(" [preinstall] ncurses 'make'"); - var make = cp.spawn("make", { - cwd: path.join(__dirname, "..", "deps", "ncurses") - }); - if(TTYU_BUILD_DEBUG) { - make.stdout.pipe(process.stdout); - make.stderr.pipe(process.stderr); - } - make.on("exit", function(code) { - if(code !== 0) throw "ncurses 'make' exited with code -" + code; - console.log(" [preinstall] finished with code -0"); - }); - }); - } else { - console.log(" [preinstall] finished with code -0"); - } -}); From e2206bb3ae60ee4c984facaf0a36894c7a49b61b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Bu=CC=88cherl?= Date: Wed, 29 Jul 2015 22:45:44 +0200 Subject: [PATCH 28/28] fixed restart problems --- .travis.yml | 2 +- include/unix.h | 10 ++++----- include/utils.h | 6 ++++-- include/win.h | 12 +++++++---- installer/index.js | 15 ++++++++++++-- installer/ncurses/download.js | 2 +- installer/util.js | 13 +++++++++--- lib/export.js | 2 ++ lib/utils.js | 5 +++++ src/core/ttyu.cc | 5 ++--- src/core/ttyu_event.cc | 7 +++---- src/unix/curses.cc | 16 +++++++-------- src/unix/emit.cc | 2 +- src/unix/goto.cc | 2 +- src/unix/main.cc | 10 ++++----- src/unix/start.cc | 19 ++++++++++++------ src/unix/stop.cc | 20 ++++++++++-------- src/unix/worker.cc | 6 +++--- src/win/start.cc | 11 ++++------ src/win/stop.cc | 2 +- src/win/worker.cc | 8 +++++--- tests/index.js | 10 ++++++++- tests/key.js | 34 +++++++++++++++++-------------- tests/mouse.js | 38 +++++++++++++++++++++++++++++++++++ 24 files changed, 173 insertions(+), 84 deletions(-) create mode 100644 tests/mouse.js diff --git a/.travis.yml b/.travis.yml index e1d2128..ab30b72 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ env: TTYU_NCURSES_REBUILD=true TTYU_BUILD_DEBUG=true TTYU_CODE_DEBUG=true node_js: - "0.10" - "0.12" - - "iojs-v2.2.0" + - "iojs-v2.3.0" install: - npm install --verbose script: diff --git a/include/unix.h b/include/unix.h index 9b99b0d..28eba1c 100644 --- a/include/unix.h +++ b/include/unix.h @@ -126,12 +126,12 @@ class ttyu_worker_c : public NanAsyncWorker { static int curses_threaded_func_thread(WINDOW *win, void *that); \ static int curses_threaded_func(WINDOW *win, ttyu_js_c *obj); \ \ - uv_thread_t curses_thread; \ + uv_thread_t *curses_thread; \ WINDOW *win; \ - uv_barrier_t barrier; \ - uv_mutex_t emitstacklock; \ - uv_mutex_t ungetlock; \ - uv_cond_t condition; \ + uv_barrier_t *barrier; \ + uv_mutex_t *emitstacklock; \ + uv_mutex_t *ungetlock; \ + uv_cond_t *condition; \ int mode; \ int x; \ int y; \ diff --git a/include/utils.h b/include/utils.h index 0b13d9c..7294b4d 100644 --- a/include/utils.h +++ b/include/utils.h @@ -54,16 +54,18 @@ #define JSFUNCTION__(_1, _2, _3, ...) _3 #define JSFUNCTION_STATIC(name, body) NAN_METHOD(name) { \ NanScope(); \ - if(1) body \ + if (1) body \ NanReturnUndefined(); \ } #define JSFUNCTION_PROTO(clas, name, body) NAN_METHOD(clas::name) { \ NanScope(); \ clas *that = ObjectWrap::Unwrap(args.This()); \ - if(1) body \ + if (1) body \ NanReturnUndefined(); \ } +#define ALLOC(c, n) reinterpret_cast(std::malloc(sizeof(c) * (n))); + #define EMIT_EVENT_OBJECT(event, cb) do { \ v8::Local __obj = NanNew(); \ switch (event->type) { \ diff --git a/include/win.h b/include/win.h index 3c2ebda..b795a3d 100644 --- a/include/win.h +++ b/include/win.h @@ -67,7 +67,7 @@ class ttyu_worker_c : public NanAsyncWorker { DBG("::~ttyu_worker_c"); uv_mutex_destroy(async_lock); ttyu_event_destroy(asyncdata_); - if(asyncdata_) + if (asyncdata_) free(asyncdata_); DBG("::~ttyu_worker_c freed"); } @@ -117,7 +117,7 @@ class ttyu_worker_c : public NanAsyncWorker { DBG("::send_ released lock"); ttyu_event_destroy(old_event); - if(old_event != NULL) + if (old_event != NULL) free(old_event); DBG(" uv_async_send"); uv_async_send(async); @@ -148,10 +148,14 @@ class ttyu_worker_c : public NanAsyncWorker { DWORD height; \ DWORD curx; \ DWORD cury; \ - uv_mutex_t emitlock; \ - uv_barrier_t barrier; \ + uv_barrier_t *barrier; \ ttyu_worker_c *worker +#define BARRIER_WAITKILL(b) if (uv_barrier_wait(b) > 0) { \ + uv_barrier_destroy(b); \ + free(b); \ + } + bool ttyu_win_scr_update(ttyu_js_c *obj, bool initial); int ttyu_win_which(DWORD code); int ttyu_win_ctrl(DWORD state); diff --git a/installer/index.js b/installer/index.js index d81b147..3a9a438 100644 --- a/installer/index.js +++ b/installer/index.js @@ -1,3 +1,6 @@ +var fs = require("fs"); +var path = require("path"); + var util = require("./util"); var ENV = { @@ -6,7 +9,8 @@ var ENV = { TTYU_CODE_DEBUG: process.env.TTYU_CODE_DEBUG || false, WIN_OS: process.platform === "win32", PKG: require("../package.json"), - CONST: require("../lib/const") + CONST: require("../lib/const"), + LIB_PATH: path.join(__dirname, "..", "deps", "ncurses", "lib") }; util.waterfall([ @@ -21,7 +25,14 @@ util.waterfall([ // generate header file require("./generate")(ENV), // prepare ncurses - require("./ncurses")(ENV) + require("./ncurses")(ENV), + // conclusion + function(cb) { + console.log(" [preinstall] finishing..."); + if(!fs.existsSync(ENV.LIB_PATH)) // to prevent ld warning in build + util.mkdirRecursiveSync(ENV.LIB_PATH); + cb(); + } ], function(err) { if(err) throw err; console.log(" [preinstall] finished with code -0"); diff --git a/installer/ncurses/download.js b/installer/ncurses/download.js index 483cd4f..7c4fd7a 100644 --- a/installer/ncurses/download.js +++ b/installer/ncurses/download.js @@ -5,7 +5,7 @@ var util = require("../util"); module.exports = function(ENV, download, cb) { if(download) { - util.rmDirRFSync(ENV.NCURSES_PATH); + util.rmRecursiveSync(ENV.NCURSES_PATH); console.log(" [preinstall/ncurses] cloning from " + ENV.NCURSES_URL); gethub("mirror", "ncurses", "master", ENV.NCURSES_PATH, function(err) { if(err) throw err; diff --git a/installer/util.js b/installer/util.js index 06932dc..642fcd2 100644 --- a/installer/util.js +++ b/installer/util.js @@ -31,19 +31,26 @@ var util = module.exports = { }); }, - rmDirRFSync: function(p) { + rmRecursiveSync: function(p) { var files = []; - if( fs.existsSync(p) ) { + if(fs.existsSync(p)) { files = fs.readdirSync(p); for(var index = 0, file; index < files.length; ++index) { file = path.join(p, files[index]); if(fs.lstatSync(file).isDirectory()) { // recurse - util.rmDirRFSync(file); + util.rmRecursiveSync(file); } else { // delete file fs.unlinkSync(file); } } fs.rmdirSync(p); } + }, + + mkdirRecursiveSync: function(p) { + if(!fs.existsSync(p)) { + util.mkdirRecursiveSync(path.join(p, "..")); + fs.mkdirSync(p); + } } }; diff --git a/lib/export.js b/lib/export.js index 70e2c98..2c81750 100644 --- a/lib/export.js +++ b/lib/export.js @@ -241,6 +241,8 @@ module.exports = function(ttyu_js_c) { }; }; ttyutil.MouseEvent = function(type, button, x, y, ctrl) { + if(!(utils.startsWith(type, "MOUSE") && type in ttyutil.EVENT)) + throw new TypeError("type is no valid mouse event type"); return { type: type, button: button, diff --git a/lib/utils.js b/lib/utils.js index b9b1857..cac60aa 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -11,5 +11,10 @@ var utils = module.exports = { c = c[0] === "#" ? c.substring(1) : c; return utils.rgb(parseInt(c.substring(0, 2), 16), parseInt(c.substring(2, 4), 16), parseInt(c.substring(4, 6), 16)); + }, + + startsWith: function(str, searchString, position) { + position = position || 0; + return str.indexOf(searchString, position) === position; } }; diff --git a/src/core/ttyu.cc b/src/core/ttyu.cc index 67d12f2..f939da2 100644 --- a/src/core/ttyu.cc +++ b/src/core/ttyu.cc @@ -35,10 +35,9 @@ JSFUNCTION(ttyu_js_c, js_running, { }) // initialize node module -void ttyu_js_c::init(DATATYPE exports, DATATYPE module){ +void ttyu_js_c::init(DATATYPE ex, DATATYPE module) { int _exports = 0; - v8::Local tpl = - NanNew(js_new); + DATATYPE tpl = NanNew(js_new); tpl->SetClassName(NanNew("ttyu_js_c")); EXPORT_METHOD(tpl, "start", js_start); diff --git a/src/core/ttyu_event.cc b/src/core/ttyu_event.cc index 333d2ab..eb61982 100644 --- a/src/core/ttyu_event.cc +++ b/src/core/ttyu_event.cc @@ -38,12 +38,12 @@ void ttyu_event_create_resize(ttyu_event_t *event) { void ttyu_event_create_key(ttyu_event_t *event, int ctrl, char *c, int code, int which) { size_t len = strlen(c); - char *ch = reinterpret_cast(std::malloc(sizeof(char) * (len + 1))); + char *ch = ALLOC(char, len + 1); memcpy(ch, c, sizeof(char) * len); ch[len] = '\0'; event->type = EVENT_KEY; - event->key = reinterpret_cast(std::malloc(sizeof(ttyu_key_t))); + event->key = ALLOC(ttyu_key_t, 1); event->mouse = NULL; event->key->ctrl = ctrl; @@ -56,8 +56,7 @@ void ttyu_event_create_mouse(ttyu_event_t *event, int type, int button, int x, int y, int ctrl) { event->type = type; event->key = NULL; - event->mouse = - reinterpret_cast(std::malloc(sizeof(ttyu_mouse_t))); + event->mouse = ALLOC(ttyu_mouse_t, 1); event->mouse->button = button; event->mouse->x = x; diff --git a/src/unix/curses.cc b/src/unix/curses.cc index 081c3d5..dc016be 100644 --- a/src/unix/curses.cc +++ b/src/unix/curses.cc @@ -30,11 +30,11 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, ttyu_js_c *obj) { event.type = EVENT_NONE; if (c == ERR) { - uv_mutex_lock(&obj->ungetlock); + uv_mutex_lock(obj->ungetlock); if (!obj->unget_stack.empty()) { ttyu_event_t ev = obj->unget_stack.front(); obj->unget_stack.pop(); - uv_mutex_unlock(&obj->ungetlock); + uv_mutex_unlock(obj->ungetlock); switch (ev.type) { case EVENT_KEY: ungetch(ev.key->code); @@ -96,7 +96,7 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, ttyu_js_c *obj) { break; } } else { - uv_mutex_unlock(&obj->ungetlock); + uv_mutex_unlock(obj->ungetlock); } return 0; } else if (c == KEY_RESIZE) { @@ -192,9 +192,9 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, ttyu_js_c *obj) { } if (event.type != EVENT_NONE) { - MUTEX_LOCK(&obj->emitstacklock, { + MUTEX_LOCK(obj->emitstacklock, { obj->emit_stack.push_back(event); - uv_cond_signal(&obj->condition); + uv_cond_signal(obj->condition); }); } return 0; @@ -202,10 +202,10 @@ int ttyu_js_c::curses_threaded_func(WINDOW *win, ttyu_js_c *obj) { int ttyu_js_c::curses_threaded_func_thread(WINDOW *win, void *that) { ttyu_js_c *obj = static_cast(that); - uv_barrier_wait(&obj->barrier); - while(curses_threaded_func(win, obj) == 0 && obj->running) usleep(100); + uv_barrier_wait(obj->barrier); + while (curses_threaded_func(win, obj) == 0 && obj->running) usleep(100); return 0; -}; +} void ttyu_js_c::curses_thread_func(void *that) { ttyu_js_c *obj = static_cast(that); diff --git a/src/unix/emit.cc b/src/unix/emit.cc index 5f069ca..193a30e 100644 --- a/src/unix/emit.cc +++ b/src/unix/emit.cc @@ -63,7 +63,7 @@ JSFUNCTION(ttyu_js_c, js_emit, { } if (event.type != EVENT_NONE) { - MUTEX_LOCK(&that->ungetlock, { + MUTEX_LOCK(that->ungetlock, { that->unget_stack.push(event); }); } diff --git a/src/unix/goto.cc b/src/unix/goto.cc index d4d28fb..f69d01e 100644 --- a/src/unix/goto.cc +++ b/src/unix/goto.cc @@ -47,7 +47,7 @@ JSFUNCTION(ttyu_js_c, js_gety, { JSFUNCTION(ttyu_js_c, js_goto, { THROW_IF_STOPPED(that); - if(args.Length() == 2) { + if (args.Length() == 2) { that->x = args[0]->Int32Value(); that->y = args[1]->Int32Value(); REFRESH_POSITION(that); diff --git a/src/unix/main.cc b/src/unix/main.cc index 504006c..bc14c5b 100644 --- a/src/unix/main.cc +++ b/src/unix/main.cc @@ -37,17 +37,17 @@ ttyu_js_c::~ttyu_js_c() { TTYU_INLINE int ttyu_get_colors() { FILE *pipe = popen("tput colors", "r"); int out = 0; - if(!pipe) return out; + if (!pipe) return out; char buffer[64]; std::string result = ""; - while(!feof(pipe)) { - if(fgets(buffer, 64, pipe) != NULL) + while (!feof(pipe)) { + if (fgets(buffer, 64, pipe) != NULL) result += buffer; } int len = static_cast(result.size()); - for(int i = len; i > 0; --i) { + for (int i = len; i > 0; --i) { char d = result[i-1]; - if(d >= '0' && d <= '9') { + if (d >= '0' && d <= '9') { out += (d - '0') * pow(10, len - i - 1); } } diff --git a/src/unix/start.cc b/src/unix/start.cc index fdc01c5..2f4257d 100644 --- a/src/unix/start.cc +++ b/src/unix/start.cc @@ -24,6 +24,7 @@ #include JSFUNCTION(ttyu_js_c, js_start, { + if (that->running) NanReturnUndefined(); that->running = TRUE; that->stop = FALSE; that->worker_run = TRUE; @@ -31,13 +32,19 @@ JSFUNCTION(ttyu_js_c, js_start, { that->x = getcurx(that->win); that->y = getcury(that->win); - uv_barrier_init(&that->barrier, 3); - uv_mutex_init(&that->emitstacklock); - uv_mutex_init(&that->ungetlock); - uv_cond_init(&that->condition); + that->curses_thread = ALLOC(uv_thread_t, 1); + that->barrier = ALLOC(uv_barrier_t, 1); + that->emitstacklock = ALLOC(uv_mutex_t, 1); + that->ungetlock = ALLOC(uv_mutex_t, 1); + that->condition = ALLOC(uv_cond_t, 1); - uv_thread_create(&that->curses_thread, ttyu_js_c::curses_thread_func, that); + uv_barrier_init(that->barrier, 3); + uv_mutex_init(that->emitstacklock); + uv_mutex_init(that->ungetlock); + uv_cond_init(that->condition); + + uv_thread_create(that->curses_thread, ttyu_js_c::curses_thread_func, that); that->check_queue(); - uv_barrier_wait(&that->barrier); + uv_barrier_wait(that->barrier); }) diff --git a/src/unix/stop.cc b/src/unix/stop.cc index 9be5be2..d8d4e42 100644 --- a/src/unix/stop.cc +++ b/src/unix/stop.cc @@ -24,18 +24,22 @@ #include JSFUNCTION(ttyu_js_c, js_stop, { - if(that->running) { + if (that->running) { that->running = FALSE; that->stop = TRUE; - uv_thread_join(&that->curses_thread); - uv_mutex_destroy(&that->emitstacklock); - uv_mutex_destroy(&that->ungetlock); - uv_cond_destroy(&that->condition); - uv_barrier_destroy(&that->barrier); + uv_thread_join(that->curses_thread); + uv_mutex_destroy(that->emitstacklock); + uv_mutex_destroy(that->ungetlock); + uv_cond_destroy(that->condition); + uv_barrier_destroy(that->barrier); + free(that->curses_thread); + free(that->emitstacklock); + free(that->ungetlock); + free(that->condition); + free(that->barrier); + endwin(); delwin(that->win); - - DBG("window deleted"); } }) diff --git a/src/unix/worker.cc b/src/unix/worker.cc index 535859d..ee03c2e 100644 --- a/src/unix/worker.cc +++ b/src/unix/worker.cc @@ -30,14 +30,14 @@ void ttyu_js_c::check_queue() { } void ttyu_worker_c::Execute() { - MUTEX_LOCK(&obj->emitstacklock,{ + MUTEX_LOCK(obj->emitstacklock, { if (obj->worker_run) { obj->worker_run = FALSE; - uv_barrier_wait(&obj->barrier); + uv_barrier_wait(obj->barrier); } while (obj->emit_stack.size() == 0) { - uv_cond_wait(&obj->condition, &obj->emitstacklock); + uv_cond_wait(obj->condition, obj->emitstacklock); } SDBG("::Execute %zu", obj->emit_stack.size()); diff --git a/src/win/start.cc b/src/win/start.cc index 091da0e..2e87131 100644 --- a/src/win/start.cc +++ b/src/win/start.cc @@ -24,12 +24,13 @@ #include JSFUNCTION(ttyu_js_c, js_start, { + if (that->running) NanReturnUndefined(); that->running = TRUE; that->stop = FALSE; DBG("::js_start()"); - uv_mutex_init(&that->emitlock); - uv_barrier_init(&that->barrier, 2); + that->barrier = ALLOC(uv_barrier_t, 1); + uv_barrier_init(that->barrier, 2); that->hin = GetStdHandle(STD_INPUT_HANDLE); that->hout = GetStdHandle(STD_OUTPUT_HANDLE); @@ -48,9 +49,5 @@ JSFUNCTION(ttyu_js_c, js_start, { DBG(" async queue start"); NanAsyncQueueWorker(that->worker); - DBG(" wait barrier"); - uv_barrier_wait(&that->barrier); - DBG(" destroy barrier"); - uv_barrier_destroy(&that->barrier); - DBG(" destroyed barrier"); + BARRIER_WAITKILL(that->barrier); }) diff --git a/src/win/stop.cc b/src/win/stop.cc index c592b16..51e6837 100644 --- a/src/win/stop.cc +++ b/src/win/stop.cc @@ -24,7 +24,7 @@ #include JSFUNCTION(ttyu_js_c, js_stop, { - if(that->running) { + if (that->running) { DBG("::stop stopping"); INPUT_RECORD in[1]; KEY_EVENT_RECORD kev; diff --git a/src/win/worker.cc b/src/win/worker.cc index 6ce6258..cde915a 100644 --- a/src/win/worker.cc +++ b/src/win/worker.cc @@ -32,7 +32,7 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, INPUT_RECORD ir[WIN_BUFFER_SIZE]; ReadConsoleInput(obj->hin, ir, WIN_BUFFER_SIZE, &readed); - if (obj->stop) { return FALSE; } // exit + if (obj->stop) { return FALSE; } // exit for (i = 0; i < readed; ++i) { if (MOUSE_EVENT == ir[i].EventType) { type = MOUSE_EVENT; @@ -69,7 +69,7 @@ bool ttyu_worker_c::execute(const ttyu_worker_c::ttyu_progress_c& progress, } break; case KEY_EVENT: { - char *ch = reinterpret_cast(std::malloc(sizeof(char) * 3)); + char *ch = ALLOC(char, 3); wcstombs(ch, &(ir[i].Event.KeyEvent.uChar.UnicodeChar), sizeof(char) * 2); ch[2] = '\0'; @@ -103,8 +103,10 @@ void ttyu_worker_c::handle(ttyu_event_t *event) { } void ttyu_worker_c::Execute() { + DBG("::Execute"); ttyu_progress_c progress(this); - uv_barrier_wait(&obj_->barrier); + BARRIER_WAITKILL(obj_->barrier); + DBG(" barrier_waited"); // loop execute until it returns false (error) while (execute(progress, obj_)) continue; } diff --git a/tests/index.js b/tests/index.js index 8af8288..760529e 100644 --- a/tests/index.js +++ b/tests/index.js @@ -1 +1,9 @@ -require("./key"); +var util = require("../installer/util"); + +util.waterfall([ + require("./key"), + require("./mouse") +], function() { + console.log("finished without errors"); + process.exit(0); +}); diff --git a/tests/key.js b/tests/key.js index 8683d1b..697a7e9 100644 --- a/tests/key.js +++ b/tests/key.js @@ -82,19 +82,23 @@ var unix_required = [ ttyu.WHICH.F24, ttyu.WHICH.BROWSER_REFRESH ]; -console.log("\r\ntest 'tests/key.js'\r"); -ttyu.start(); -(function check(i, cb) { - var listener = function(ev) { - assert.equal(ev.which, unix_required[i], " which should be " + - unix_required[i]); - ttyu.off(ttyu.EVENT.KEY, listener); - if(i <= 0) cb(); else check(i - 1, cb); - }; - ttyu.on(ttyu.EVENT.KEY, listener); - ttyu.emit(ttyu.KeyEvent(unix_required[i], 0)); -})(unix_required.length - 1, function() { - ttyu.stop(); - console.log("test 'tests/key.js' passed\r"); -}); +module.exports = function(cb) { + console.log("\r\ntest 'tests/key.js'\r"); + ttyu.start(); + + (function check(i, cb) { + var listener = function(ev) { + assert.equal(ev.which, unix_required[i], " which should be " + + unix_required[i]); + ttyu.off(ttyu.EVENT.KEY, listener); + if(i <= 0) cb(); else check(i - 1, cb); + }; + ttyu.on(ttyu.EVENT.KEY, listener); + ttyu.emit(ttyu.KeyEvent(unix_required[i], 0)); + })(unix_required.length - 1, function() { + ttyu.stop(); + console.log("test 'tests/key.js' passed\r"); + cb(); + }); +}; diff --git a/tests/mouse.js b/tests/mouse.js new file mode 100644 index 0000000..17c4899 --- /dev/null +++ b/tests/mouse.js @@ -0,0 +1,38 @@ +var ttyu = require("../index"); +var assert = require("assert"); +var mouseEvent = []; + +// mouse up & mouse down +for(var type in ttyu.MOUSE) { + mouseEvent.push([ttyu.EVENT.MOUSEUP, ttyu.MOUSE[type]]); + mouseEvent.push([ttyu.EVENT.MOUSEDOWN, ttyu.MOUSE[type]]); +} + +module.exports = function(cb) { + console.log("\r\ntest 'tests/mouse.js'\r"); + ttyu.start(); + + (function check(i, cb) { + var event = ttyu.MouseEvent.call(null, mouseEvent[i][0], + mouseEvent[i][1], Math.round(Math.random() * 10), + Math.round(Math.random() * 10), 0); + var listener = function(ev) { + console.log(JSON.stringify(ev)); + assert.equal(ev.type, event.type); + assert.equal(ev.button, event.button); + assert.equal(ev.x, event.x); + assert.equal(ev.y, event.y); + assert.equal(ev.ctrl, event.ctrl); + ttyu.off(event.type, listener); + console.log(" done!\r"); + if(i <= 0) cb(); else check(i - 1, cb); + }; + ttyu.on(event.type, listener); + ttyu.emit(event); + console.log("testing " + JSON.stringify(event) + " ... "); + })(mouseEvent.length - 1, function() { + ttyu.stop(); + console.log("test 'tests/mouse.js' passed\r"); + cb(); + }); +};