Socket
Socket
Sign inDemoInstall

elgato-stream-deck

Package Overview
Dependencies
Maintainers
2
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

elgato-stream-deck - npm Package Compare versions

Comparing version 1.0.0 to 1.1.0

11

CHANGELOG.md

@@ -0,1 +1,12 @@

<a name="1.1.0"></a>
# [1.1.0](https://github.com/Lange/node-elgato-stream-deck/compare/v1.0.0...v1.1.0) (2017-05-18)
### Features
* add `write` method ([0085d87](https://github.com/Lange/node-elgato-stream-deck/commit/0085d87))
* add `fillColor`, `fillImage`, and `fillImageFromFile` methods ([5fe46ef](https://github.com/Lange/node-elgato-stream-deck/commit/5fe46ef))
<a name="1.0.0"></a>

@@ -2,0 +13,0 @@ # 1.0.0 (2017-05-17)

138

index.js

@@ -8,36 +8,138 @@ 'use strict';

const HID = require('node-hid');
const sharp = require('sharp');
const NUM_KEYS = 15;
const PAGE_PACKET_SIZE = 8191;
const NUM_FIRST_PAGE_PIXELS = 2583;
const NUM_SECOND_PAGE_PIXELS = 2601;
const ICON_SIZE = 72;
const NUM_TOTAL_PIXELS = NUM_FIRST_PAGE_PIXELS + NUM_SECOND_PAGE_PIXELS;
const keyState = new Array(NUM_KEYS).fill(false);
const emitter = new EventEmitter();
const devices = HID.devices();
const streamDecks = devices.filter(device => {
const connectedStreamDecks = devices.filter(device => {
return device.product === 'Stream Deck' && device.manufacturer === 'Elgato Systems';
});
if (streamDecks.length > 1) {
if (connectedStreamDecks.length > 1) {
throw new Error('More than one Stream Deck is connected. This is unsupported at this time.');
}
const streamDeck = new HID.HID(streamDecks[0].path);
class StreamDeck extends EventEmitter {
constructor(device) {
super();
this.device = device;
streamDeck.on('data', data => {
for (let i = 0; i < NUM_KEYS; i++) {
const keyPressed = Boolean(data[i + 1]);
if (keyPressed !== keyState[i]) {
if (keyPressed) {
emitter.emit('down', i);
} else {
emitter.emit('up', i);
this.device.on('data', data => {
// The first byte is a report ID, the last byte appears to be padding
// strip these out for now.
data = data.slice(1, data.length - 1);
for (let i = 0; i < NUM_KEYS; i++) {
const keyPressed = Boolean(data[i]);
if (keyPressed !== keyState[i]) {
if (keyPressed) {
this.emit('down', i);
} else {
this.emit('up', i);
}
}
keyState[i] = keyPressed;
}
});
this.device.on('error', err => {
this.emit('error', err);
});
}
write(buffer) {
return this.device.write(StreamDeck.bufferToIntArray(buffer));
}
fillColor(keyIndex, r, g, b) {
const pixel = Buffer.from([b, g, r]);
this._writePage1(keyIndex, Buffer.alloc(NUM_FIRST_PAGE_PIXELS * 3, pixel));
this._writePage2(keyIndex, Buffer.alloc(NUM_SECOND_PAGE_PIXELS * 3, pixel));
}
fillImage(keyIndex, imageBuffer) {
if (imageBuffer.length !== 15552) {
throw new Error(`Expected image buffer of length 15552, got length ${imageBuffer.length}`);
}
keyState[i] = keyPressed;
let pixels = [];
for (let r = 0; r < ICON_SIZE; r++) {
const row = [];
const start = r * 3 * ICON_SIZE;
for (let i = start; i < start + (ICON_SIZE * 3); i += 3) {
const r = imageBuffer.readUInt8(i);
const g = imageBuffer.readUInt8(i + 1);
const b = imageBuffer.readUInt8(i + 2);
row.push(b, g, r);
}
pixels = pixels.concat(row.reverse());
}
const firstPagePixels = pixels.slice(0, NUM_FIRST_PAGE_PIXELS * 3);
const secondPagePixels = pixels.slice(NUM_FIRST_PAGE_PIXELS * 3, NUM_TOTAL_PIXELS * 3);
this._writePage1(keyIndex, Buffer.from(firstPagePixels));
this._writePage2(keyIndex, Buffer.from(secondPagePixels));
}
});
streamDeck.on('error', err => {
emitter.emit('error', err);
});
fillImageFromFile(keyIndex, filePath) {
return sharp(filePath)
.flatten() // Eliminate alpha channel, if any.
.resize(this.ICON_SIZE, this.ICON_SIZE)
.raw()
.toBuffer()
.then(buffer => {
return this.fillImage(keyIndex, buffer);
});
}
module.exports = emitter;
_writePage1(keyIndex, buffer) {
const header = Buffer.from([
0x02, 0x01, 0x01, 0x00, 0x00, keyIndex + 1, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x42, 0x4d, 0xf6, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00,
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x3c, 0x00, 0x00, 0xc4, 0x0e,
0x00, 0x00, 0xc4, 0x0e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]);
const packetWithHeader = Buffer.concat([header, buffer]);
const numZeroesToFill = PAGE_PACKET_SIZE - packetWithHeader.length;
const packet = Buffer.concat([packetWithHeader, Buffer.alloc(numZeroesToFill)]);
return this.write(packet);
}
_writePage2(keyIndex, buffer) {
const header = Buffer.from([
0x02, 0x01, 0x02, 0x00, 0x01, keyIndex + 1, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]);
const packetWithHeader = Buffer.concat([header, buffer]);
const numZeroesToFill = PAGE_PACKET_SIZE - packetWithHeader.length;
const packet = Buffer.concat([packetWithHeader, Buffer.alloc(numZeroesToFill)]);
return this.write(packet);
}
get ICON_SIZE() {
return ICON_SIZE;
}
static bufferToIntArray(buffer) {
const array = [];
for (const pair of buffer.entries()) {
array.push(pair[1]);
}
return array;
}
}
module.exports = new StreamDeck(new HID.HID(connectedStreamDecks[0].path));
{
"name": "elgato-stream-deck",
"version": "1.0.0",
"version": "1.1.0",
"description": "A npm module for interfacing with the Elgato Stream Deck",

@@ -12,2 +12,3 @@ "main": "index.js",

"eslint-config-xo": "^0.18.2",
"sharp": "^0.17.3",
"weallbehave": "^1.2.0",

@@ -39,4 +40,17 @@ "weallcontribute": "^1.0.8"

"email": "email@alexvan.camp",
"url": "https://alexvan.camp/"
"url": "https://alexvan.camp/",
"twitter": "vancamp"
},
"contributors": [
{
"name": "Richard Fox",
"twitter": "ProbablePrime"
},
{
"name": "Chris Hanel",
"twitter": "chrishanel",
"email": "chrishanel@gmail.com",
"url": "http://www.chrishanel.com/"
}
],
"license": "MIT",

@@ -43,0 +57,0 @@ "bugs": {

@@ -1,3 +0,5 @@

# elgato-stream-deck [![npm version](https://img.shields.io/npm/v/elgato-stream-deck.svg)](https://npm.im/elgato-stream-deck) [![license](https://img.shields.io/npm/l/elgato-stream-deck.svg)](https://npm.im/elgato-stream-deck) [![Travis](https://img.shields.io/travis/lange/elgato-stream-deck.svg)](https://travis-ci.org/lange/elgato-stream-deck)
# elgato-stream-deck [![npm version](https://img.shields.io/npm/v/elgato-stream-deck.svg)](https://npm.im/elgato-stream-deck) [![license](https://img.shields.io/npm/l/elgato-stream-deck.svg)](https://npm.im/elgato-stream-deck) [![Travis](https://travis-ci.org/Lange/node-elgato-stream-deck.svg?branch=master)](https://travis-ci.org/Lange/node-elgato-stream-deck) [![Join the chat at https://gitter.im/node-elgato-stream-deck/Lobby](https://badges.gitter.im/node-elgato-stream-deck/Lobby.svg)](https://gitter.im/node-elgato-stream-deck/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![alt text](media/streamdeck_ui.png "elgato-stream-deck")
[`elgato-stream-deck`](https://github.com/lange/elgato-stream-deck) is a Node.js library for interfacing

@@ -14,4 +16,9 @@ with the [Elgato Stream Deck](https://www.elgato.com/en/gaming/stream-deck).

* [Features](#features)
* [PLanned Features](#planned-features)
* [Planned Features](#planned-features)
* [Contributing](#contributing)
* [API](#api)
* [`write`](#write)
* [`fillColor`](#fill-color)
* [`fillImageFromFile`](#fill-image-from-file)
* [`fillImage`](#fill-image)
* [Events](#events)

@@ -25,3 +32,5 @@ * [`down`](#down)

```javascript
const path = require('path');
const streamDeck = require('elgato-stream-deck')
streamDeck.on('down', keyIndex => {

@@ -38,2 +47,12 @@ console.log('key %d down', keyIndex);

});
// Fill the second button from the left in the first row with an image of the GitHub logo.
// This is asynchronous and returns a promise.
streamDeck.fillImageFromFile(3, path.resolve(__dirname, 'github_logo.png')).then(() => {
console.log('Successfully wrote a GitHub logo to key 3.');
});
// Fill the first button form the left in the first row with a solid red color. This is synchronous.
streamDeck.fillColor(4, 255, 0, 0);
console.log('Successfully wrote a red square to key 4.');
```

@@ -44,2 +63,3 @@

* Key `down` and key `up` events
* Fill keys with images or solid RGB colors

@@ -49,3 +69,2 @@ ### Planned Features

* Key combinations
* Send new images to keys
* Support "pages" feature from the official Elgato Stream Deck software

@@ -61,2 +80,69 @@

### API
#### <a name="write"></a> `> streamDeck.write(buffer) -> undefined`
Synchronously writes an arbitrary [`Buffer`](https://nodejs.org/api/buffer.html) instance to the Stream Deck.
Throws if an error is encountered during the write operation.
##### Example
```javascript
// Writes 16 bytes of zero to the Stream Deck.
streamDeck.write(Buffer.alloc(16));
```
#### <a name="fill-color"></a> `> streamDeck.fillColor(keyIndex, r, g, b) -> undefined`
Synchronously sets the given `keyIndex`'s screen to a solid RGB color.
##### Example
```javascript
// Turn key 4 (the top left key) solid red.
streamDeck.fillColor(4, 255, 0, 0);
```
#### <a name="fill-image-from-file"></a> `> streamDeck.fillImageFromFile(keyIndex, filePath) -> Promise`
Asynchronously reads an image from `filePath` and sets the given `keyIndex`'s screen to that image.
Automatically scales the image to 72x72 and strips out the alpha channel.
If necessary, the image will be center-cropped to fit into a square.
##### Example
```javascript
// Fill the second button from the left in the first row with an image of the GitHub logo.
streamDeck.fillImageFromFile(3, path.resolve(__dirname, 'github_logo.png'))
.then(() => {
console.log('Successfully wrote a GitHub logo to key 3.');
})
.catch(err => {
console.error(err);
});
```
#### <a name="fill-image"></a> `> streamDeck.fillImage(keyIndex, buffer) -> undefined`
Synchronously writes a buffer of 72x72 RGB image data to the given `keyIndex`'s screen.
The buffer must be exactly 15552 bytes in length. Any other length will result in an error being thrown.
##### Example
```javascript
// Fill the third button from the left in the first row with an image of the GitHub logo.
const sharp = require('sharp'); // See http://sharp.dimens.io/en/stable/ for full docs on this great library!
sharp(path.resolve(__dirname, 'github_logo.png'))
.flatten() // Eliminate alpha channel, if any.
.resize(streamDeck.ICON_SIZE, streamDeck.ICON_SIZE) // Scale down to the right size, cropping if necessary.
.raw() // Give us uncompressed RGB
.toBuffer()
.then(buffer => {
return streamDeck.fillImage(2, buffer);
})
.catch(err => {
console.error(err);
});
```
### Events

@@ -66,3 +152,3 @@

Fired whenever a key is pressed. `keyIndex` is the 0-15 numerical index of that key.
Fired whenever a key is pressed. `keyIndex` is the 0-14 numerical index of that key.

@@ -79,3 +165,3 @@ ##### Example

Fired whenever a key is released. `keyIndex` is the 0-15 numerical index of that key.
Fired whenever a key is released. `keyIndex` is the 0-14 numerical index of that key.

@@ -82,0 +168,0 @@ ##### Example

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc