├── .gitignore ├── README.md ├── binding.gyp ├── examples ├── buttons.js └── test.js ├── index.js ├── package.json └── src └── touchscreen.cc /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | 3 | .idea/ 4 | *.iml 5 | *.iws 6 | 7 | .DS_Store 8 | .AppleDouble 9 | .LSOverride 10 | ._* 11 | 12 | build/ 13 | node_modules 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | node-pitft-touch 2 | ================ 3 | 4 | ### A [NodeJS](http://nodejs.org) module that give you access to the touch screen on the Adafruit PiTFT family of displays for the [Raspberry Pi](http://www.raspberrypi.org) computer. 5 | 6 | ## Author 7 | - Werner Vesterås 8 | 9 | ## Installation 10 | 11 | ```bash 12 | $ npm install pitft-touch 13 | ``` 14 | 15 | ## Examples 16 | 17 | See the [examples](https://github.com/vesteraas/node-pitft-touch/tree/master/examples) directory. 18 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "ts", 5 | "include_dirs": [ 6 | "= gui[element].pos[0] && x < (gui[element].pos[0] + gui[element].size[0])) { 40 | if (y >= gui[element].pos[1] && y < (gui[element].pos[1] + gui[element].size[1])) { 41 | return element; 42 | } 43 | } 44 | } 45 | } 46 | 47 | return null; 48 | } 49 | 50 | fb.clear(); 51 | for (var element in gui) { 52 | if (gui.hasOwnProperty(element)) { 53 | drawElement(element); 54 | } 55 | } 56 | fb.blit(); 57 | 58 | var elementUnderCursor, pressedElement; 59 | 60 | touchscreen("/dev/input/touchscreen", function(err, data) { 61 | if (err) { 62 | throw err; 63 | } 64 | 65 | var screenX = ((270 - 50) / (693 - 3307)) * data.x + 320; 66 | var screenY = ((190 - 50) / (3220 - 996)) * data.y; 67 | 68 | if (pressedElement && data.touch == 0) { 69 | gui[pressedElement].pressed = false; 70 | drawElement(pressedElement); 71 | } 72 | 73 | elementUnderCursor = getElementUnderCursor(screenX, screenY); 74 | 75 | if (elementUnderCursor) { 76 | if (data.touch == 1) { 77 | pressedElement = elementUnderCursor; 78 | gui[pressedElement].pressed = true; 79 | drawElement(pressedElement); 80 | console.log(gui[pressedElement].text.caption); 81 | } 82 | } 83 | 84 | fb.blit(); 85 | }); 86 | -------------------------------------------------------------------------------- /examples/test.js: -------------------------------------------------------------------------------- 1 | var touchscreen = require("../index"); 2 | 3 | var touchCount = 0; 4 | 5 | touchscreen("/dev/input/touchscreen", function(err, data) { 6 | if (err) { 7 | throw err; 8 | } 9 | 10 | // Stop after 10 touches 11 | if (touchCount++ == 10) { 12 | data.stop = true; 13 | } 14 | 15 | console.log(data); 16 | }); 17 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var bindings = require("bindings")("ts"); 2 | 3 | module.exports = bindings; 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pitft-touch", 3 | "version": "0.0.6", 4 | "description": "A NodeJS module that gives you access to the Adafruit PiTFT touch screen", 5 | "main": "index.js", 6 | "author": "Werner Vesteraas ", 7 | "license": { 8 | "type": "MIT", 9 | "url": "http://opensource.org/licenses/MIT" 10 | }, 11 | "keywords": ["raspberry pi", "touchscreen", "pitft"], 12 | "dependencies": { 13 | "bindings": "^1.2.1", 14 | "nan": "^2.1.0" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/vesteraas/node-pitft-touch.git" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/touchscreen.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace v8; 9 | using namespace node; 10 | 11 | NAN_METHOD(Async); 12 | void AsyncWork(uv_work_t* req); 13 | void AsyncAfter(uv_work_t* req); 14 | 15 | struct TouchInfo { 16 | int fileDescriptor; 17 | Nan::Callback *callback; 18 | 19 | bool error; 20 | std::string errorMessage; 21 | 22 | struct input_event inputEvents[64]; 23 | int read; 24 | 25 | int x; 26 | int y; 27 | int pressure; 28 | 29 | bool stop; 30 | }; 31 | 32 | NAN_METHOD(Async) { 33 | // Nan::HandleScope scope; 34 | 35 | if (info[0]->IsUndefined()) { 36 | return Nan::ThrowError("No parameters specified"); 37 | } 38 | 39 | if (!info[0]->IsString()) { 40 | return Nan::ThrowError("First parameter should be a string"); 41 | } 42 | 43 | if (info[1]->IsUndefined()) { 44 | return Nan::ThrowError("No callback function specified"); 45 | } 46 | 47 | if (!info[1]->IsFunction()) { 48 | return Nan::ThrowError("Second argument should be a function"); 49 | } 50 | 51 | Nan::Utf8String *path = new Nan::Utf8String(info[0]); 52 | 53 | TouchInfo* touchInfo = new TouchInfo(); 54 | touchInfo->fileDescriptor = open(**path, O_RDONLY); 55 | touchInfo->callback = new Nan::Callback(info[1].As()); 56 | touchInfo->error = false; 57 | touchInfo->stop = false; 58 | 59 | uv_work_t *req = new uv_work_t(); 60 | req->data = touchInfo; 61 | 62 | int status = uv_queue_work(uv_default_loop(), req, AsyncWork, (uv_after_work_cb)AsyncAfter); 63 | 64 | assert(status == 0); 65 | 66 | info.GetReturnValue().SetUndefined(); 67 | } 68 | 69 | void AsyncWork(uv_work_t* req) { 70 | TouchInfo* touchInfo = static_cast(req->data); 71 | 72 | touchInfo->read = read(touchInfo->fileDescriptor, touchInfo->inputEvents, sizeof(struct input_event) * 64); 73 | 74 | if (touchInfo->read < (int) sizeof(struct input_event)) { 75 | touchInfo->error = true; 76 | touchInfo->errorMessage = "Read problem"; 77 | } 78 | } 79 | 80 | void AsyncAfter(uv_work_t* req) { 81 | Nan::HandleScope scope; 82 | 83 | TouchInfo* touchInfo = static_cast(req->data); 84 | 85 | if (touchInfo->error) { 86 | Local err = Exception::Error(Nan::New(touchInfo->errorMessage.c_str()).ToLocalChecked()); 87 | 88 | const unsigned argc = 1; 89 | Local argv[argc] = { err }; 90 | 91 | TryCatch try_catch; 92 | 93 | touchInfo->callback->Call(Nan::GetCurrentContext()->Global(), argc, argv); 94 | 95 | if (try_catch.HasCaught()) { 96 | FatalException(try_catch); 97 | } 98 | } else { 99 | for (unsigned i = 0; i < touchInfo->read / sizeof(struct input_event); i++) { 100 | if (touchInfo->inputEvents[i].type == EV_SYN) { 101 | } else if (touchInfo->inputEvents[i].type == EV_ABS && (touchInfo->inputEvents[i].code == ABS_Y)) { 102 | touchInfo->x = touchInfo->inputEvents[i].value; 103 | } else if (touchInfo->inputEvents[i].type == EV_ABS && (touchInfo->inputEvents[i].code == ABS_X)) { 104 | touchInfo->y = touchInfo->inputEvents[i].value; 105 | } else if (touchInfo->inputEvents[i].type == EV_ABS && (touchInfo->inputEvents[i].code == ABS_PRESSURE)) { 106 | touchInfo->pressure = touchInfo->inputEvents[i].value; 107 | } else if (touchInfo->inputEvents[i].type == EV_KEY && (touchInfo->inputEvents[i].code == BTN_TOUCH)) { 108 | Local touch = Nan::New(); 109 | touch->Set(Nan::New("x").ToLocalChecked(), Nan::New(touchInfo->x)); 110 | touch->Set(Nan::New("y").ToLocalChecked(), Nan::New(touchInfo->y)); 111 | touch->Set(Nan::New("pressure").ToLocalChecked(), Nan::New(touchInfo->pressure)); 112 | touch->Set(Nan::New("touch").ToLocalChecked(), Nan::New(touchInfo->inputEvents[i].value)); 113 | touch->Set(Nan::New("stop").ToLocalChecked(), Nan::New(touchInfo->stop)); 114 | 115 | const unsigned argc = 2; 116 | Local argv[argc] = { Nan::Null(), touch }; 117 | 118 | TryCatch try_catch; 119 | 120 | touchInfo->callback->Call(Nan::GetCurrentContext()->Global(), argc, argv); 121 | touchInfo->stop = touch->Get(Nan::New("stop").ToLocalChecked())->BooleanValue(); 122 | 123 | if (try_catch.HasCaught()) { 124 | FatalException(try_catch); 125 | } 126 | } 127 | } 128 | 129 | if (touchInfo->stop) { 130 | delete touchInfo->callback; 131 | delete touchInfo; 132 | delete req; 133 | } else { 134 | int status = uv_queue_work(uv_default_loop(), req, AsyncWork, (uv_after_work_cb)AsyncAfter); 135 | assert(status == 0); 136 | } 137 | } 138 | } 139 | 140 | void InitAll(Handle exports, Handle module) { 141 | Nan::HandleScope scope; 142 | 143 | module->Set(Nan::New("exports").ToLocalChecked(), 144 | Nan::New(Async)->GetFunction()); 145 | } 146 | 147 | NODE_MODULE(ts, InitAll) 148 | --------------------------------------------------------------------------------