├── index.js ├── .npmignore ├── examples ├── wave.js ├── wave2.js ├── wave4.js ├── breathe2.js ├── wave3.js ├── color.js ├── blink.js ├── sample.js ├── sample2.js ├── blinkMulti.js ├── breathe.js ├── flow.js └── msi-kbd.js ├── .gitignore ├── .travis.yml ├── test ├── main.js ├── findKeyboard.js └── setColor.js ├── lib ├── constants.json ├── setColor.js ├── findKeyboard.js └── setMode.js ├── package.json ├── LICENSE └── README.md /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/findKeyboard'); 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | node_modules 4 | build 5 | *.node 6 | components 7 | -------------------------------------------------------------------------------- /examples/wave.js: -------------------------------------------------------------------------------- 1 | var keyboard = require('../')(); 2 | 3 | keyboard.mode('wave', 'blue'); 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.log 3 | node_modules 4 | build 5 | *.node 6 | components 7 | **/.*.s[a-w][a-z] 8 | -------------------------------------------------------------------------------- /examples/wave2.js: -------------------------------------------------------------------------------- 1 | var keyboard = require('../')(); 2 | 3 | keyboard.mode('wave', { 4 | left: 'red', 5 | middle: 'green', 6 | right: 'blue' 7 | }, 5); 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | before_install: 3 | - sudo apt-get install libudev-dev libusb-dev libusb-1.0-0.dev 4 | addons: 5 | apt: 6 | update: true 7 | node_js: 8 | - 0.11 9 | - 10 10 | - 11 11 | -------------------------------------------------------------------------------- /examples/wave4.js: -------------------------------------------------------------------------------- 1 | var keyboard = require('../')(); 2 | 3 | keyboard.mode('wave', { 4 | left: {color:'blue',secondary:'red'}, 5 | middle: {color:'blue', secondary:'red'}, 6 | right: {color:'blue', secondary:'red'}, 7 | }, 2); 8 | -------------------------------------------------------------------------------- /examples/breathe2.js: -------------------------------------------------------------------------------- 1 | var keyboard = require('../')(); 2 | 3 | keyboard.mode('breathe', { 4 | left: {color:'blue',secondary:'red'}, 5 | middle: {color:'blue', secondary:'red'}, 6 | right: {color:'blue', secondary:'red'}, 7 | }); 8 | -------------------------------------------------------------------------------- /examples/wave3.js: -------------------------------------------------------------------------------- 1 | var keyboard = require('../')(); 2 | 3 | keyboard.mode('wave', { 4 | left: {color:'green',secondary:'blue'}, 5 | middle: {color:'blue', secondary:'green'}, 6 | right: {color:'green', secondary:'blue'} 7 | }, 2); 8 | -------------------------------------------------------------------------------- /test/main.js: -------------------------------------------------------------------------------- 1 | var keyboard = require('../')(); 2 | var should = require('should'); 3 | require('mocha'); 4 | 5 | describe('msi-keyboard', function() { 6 | it('should export a keyboard', function(done) { 7 | should.exist(keyboard); 8 | keyboard.close(); 9 | done(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /examples/color.js: -------------------------------------------------------------------------------- 1 | var keyboard = require('../')(); 2 | 3 | keyboard.color('left', { 4 | color: 'rgba(200, 0, 0)', 5 | intensity: 'high' 6 | }); 7 | keyboard.color('middle', { 8 | color: 'green', 9 | intensity: 'high' 10 | }); 11 | keyboard.color('right', { 12 | color: '#4654BD', 13 | intensity: 'high' 14 | }); 15 | -------------------------------------------------------------------------------- /examples/blink.js: -------------------------------------------------------------------------------- 1 | var keyboard = require('../')(); 2 | 3 | keyboard.color('left', { 4 | color: 'red', 5 | intensity: 'med' 6 | }); 7 | keyboard.color('middle', { 8 | color: 'green', 9 | intensity: 'med' 10 | }); 11 | keyboard.color('right', { 12 | color: 'blue', 13 | intensity: 'med', 14 | }); 15 | 16 | 17 | keyboard.blink(750); 18 | -------------------------------------------------------------------------------- /examples/sample.js: -------------------------------------------------------------------------------- 1 | var keyboard = require('../')(); 2 | 3 | keyboard.mode('breathe', { 4 | left: {color: 'red', intensity: 'med'}, 5 | middle :{color:'green', intensity:'med'}, 6 | right: {color:'green', intensity:'med'} 7 | }); 8 | 9 | 10 | 11 | keyboard.blink(['left'], 750); 12 | 13 | setTimeout(keyboard.stopBlink, 5000); 14 | 15 | -------------------------------------------------------------------------------- /examples/sample2.js: -------------------------------------------------------------------------------- 1 | var keyboard = require('../')(); 2 | 3 | keyboard.mode('breathe', { 4 | left: { 5 | color: 'red', 6 | intensity: 'high', 7 | secondary:'green' 8 | }, 9 | right: { 10 | color:'green', 11 | intensity:'med' 12 | } 13 | }); 14 | 15 | 16 | keyboard.blink(['left'], 200); 17 | 18 | setTimeout(keyboard.stopBlink, 500); 19 | 20 | -------------------------------------------------------------------------------- /examples/blinkMulti.js: -------------------------------------------------------------------------------- 1 | var keyboard = require('../')(); 2 | 3 | // Set colors before calling blink() 4 | keyboard.color('left', { 5 | color: 'red', 6 | intensity: 'med' 7 | }); 8 | keyboard.color('middle', { 9 | color: 'green', 10 | intensity: 'med' 11 | }); 12 | keyboard.color('right', { 13 | color: 'blue', 14 | intensity: 'med', 15 | }); 16 | 17 | 18 | keyboard.blink(['left','right'], 750); 19 | -------------------------------------------------------------------------------- /test/findKeyboard.js: -------------------------------------------------------------------------------- 1 | var findKeyboard = require('../lib/findKeyboard'); 2 | var should = require('should'); 3 | require('mocha'); 4 | 5 | describe('msi-keyboard', function() { 6 | describe('findKeyboard()', function() { 7 | it('should find the keyboard', function(done) { 8 | var keyboard = findKeyboard(); 9 | should.exist(keyboard); 10 | should.exist(keyboard.write); 11 | keyboard.close(); 12 | done(); 13 | }); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /lib/constants.json: -------------------------------------------------------------------------------- 1 | { 2 | "regions": { 3 | "left": 1, 4 | "middle": 2, 5 | "right": 3, 6 | "logo": 4, 7 | "frontLeft": 5, 8 | "frontRight" : 6, 9 | "touchpad" : 7 10 | }, 11 | "colors": { 12 | "black": 0, 13 | "red": 1, 14 | "orange": 2, 15 | "yellow": 3, 16 | "green": 4, 17 | "cyan": 5, 18 | "blue": 6, 19 | "purple": 7, 20 | "white": 8 21 | }, 22 | "levels": { 23 | "light": 0.25, 24 | "low": 0.50, 25 | "med": 0.75, 26 | "high": 1.00 27 | }, 28 | "modes": { 29 | "normal": 1, 30 | "gaming": 2, 31 | "breathe": 3, 32 | "demo": 4, 33 | "wave": 5 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "msi-keyboard", 3 | "description": "MSI Keyboard LED Controller", 4 | "version": "0.7.0", 5 | "homepage": "http://github.com/stevelacy/msi-keyboard", 6 | "repository": "git://github.com/stevelacy/msi-keyboard.git", 7 | "author": "Steve Lacy (http://slacy.me)", 8 | "main": "./index.js", 9 | "dependencies": { 10 | "color": "^3.1.2", 11 | "node-hid": "^2.1.1" 12 | }, 13 | "devDependencies": { 14 | "mocha": "^7.1.1", 15 | "should": "^13.2.3" 16 | }, 17 | "scripts": { 18 | "test": "mocha test/main.js test/*.js" 19 | }, 20 | "engines": { 21 | "node": ">= 0.4.0" 22 | }, 23 | "license": "MIT" 24 | } 25 | -------------------------------------------------------------------------------- /test/setColor.js: -------------------------------------------------------------------------------- 1 | var findKeyboard = require('../lib/findKeyboard'); 2 | var setColor = require('../lib/setColor'); 3 | require('mocha'); 4 | 5 | describe('msi-keyboard', function() { 6 | describe('setColor()', function() { 7 | it('should set the color', function(done) { 8 | var keyboard = findKeyboard(); 9 | setColor(keyboard, 'left', { red: () => 255, green: () => 0, blue: () => 0 }, 'high'); 10 | setColor(keyboard, 'right', { red: () => 0, green: () => 255, blue: () => 0 }, 'high'); 11 | setColor(keyboard, 'middle', { red: () => 0, green: () => 0, blue: () => 255 }, 'high'); 12 | keyboard.close(); 13 | done(); 14 | }); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /examples/breathe.js: -------------------------------------------------------------------------------- 1 | var keyboard = require('../')(); 2 | 3 | keyboard.mode('breathe', 'green', 'red', 'yellow'); //Keyboard will pulse from green, red, and yellow (in the left, middle, and right areas, respectively) high intensity to black (which is the default secondary color). 4 | 5 | /* 6 | keyboard.mode('breathe', 7 | {color:'sky', intensity:'high', secondary:'purple'}, //Left area will alternate from sky to purple, with high light intensity 8 | {color:'red', intensity:'high', secondary:{intensity:'light'}}, //Middle area will alternate from dark red (high intensity red) to a light pink (light intensity red) 9 | {primary:{color:'green'},secondary:{color:'black'}}, //Right area will alternate from green (high intensity by default) to darkness (black) 10 | 1); //Pattern will repeat every 1 second 11 | */ 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Fractal 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /examples/flow.js: -------------------------------------------------------------------------------- 1 | var keyboard = require('../')(); 2 | var color = require('color'); 3 | var sleep = require('sleep'); 4 | 5 | 6 | 7 | var left = color({h: 0, s: 255, v: 255}); 8 | var middle = color({h: 60, s: 255, v: 255}); 9 | var right = color({h: 120, s: 255, v: 255}); 10 | 11 | 12 | 13 | while(true){ 14 | 15 | sleep.msleep(10); 16 | 17 | keyboard.color('left', { 18 | color: left, 19 | intensity: 'high' 20 | }); 21 | 22 | keyboard.color('logo', { 23 | color: left, 24 | intensity: 'high' 25 | }); 26 | 27 | keyboard.color('frontLeft', { 28 | color: left, 29 | intensity: 'high' 30 | }); 31 | 32 | keyboard.color('middle', { 33 | color: middle, 34 | intensity: 'high' 35 | }); 36 | 37 | keyboard.color('touchpad', { 38 | color: middle, 39 | intensity: 'high' 40 | }); 41 | 42 | 43 | keyboard.color('right', { 44 | color: right, 45 | intensity: 'high' 46 | }); 47 | 48 | keyboard.color('frontRight', { 49 | color: right, 50 | intensity: 'high' 51 | }); 52 | 53 | 54 | 55 | left = left.rotate(1); 56 | middle = middle.rotate(1); 57 | right = right.rotate(1); 58 | 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /lib/setColor.js: -------------------------------------------------------------------------------- 1 | var constants = require('./constants'); 2 | var setMode = require('./setMode'); 3 | 4 | module.exports = function(keyboard, region, color, intensity){ 5 | if (!region) throw 'missing region'; 6 | if (!color) throw 'missing color'; 7 | if (!intensity) intensity = 'high'; 8 | 9 | if (typeof constants.regions[region] === 'undefined') throw 'invalid region'; 10 | if (typeof constants.levels[intensity] === 'undefined') throw 'invalid intensity'; 11 | if ( (typeof color.red === 'undefined') 12 | || (typeof color.green === 'undefined') 13 | || (typeof color.blue === 'undefined') 14 | ) throw 'invalid color'; 15 | 16 | var activate = []; 17 | // header 18 | activate[0] = 1; 19 | activate[1] = 2; 20 | activate[2] = 64; // set color 21 | activate[3] = constants.regions[region]; 22 | activate[4] = color.red() * constants.levels[intensity]; 23 | activate[5] = color.green() * constants.levels[intensity]; 24 | activate[6] = color.blue() * constants.levels[intensity]; 25 | activate[7] = 0; 26 | 27 | keyboard.sendFeatureReport(activate); 28 | setMode(keyboard, keyboard.currentMode || 'normal'); 29 | 30 | keyboard.current[region] = { 31 | intensity: intensity, 32 | color: color 33 | }; 34 | 35 | return keyboard; 36 | }; 37 | -------------------------------------------------------------------------------- /examples/msi-kbd.js: -------------------------------------------------------------------------------- 1 | // msi-kbd - Change color settings of MSI laptop keyboards 2 | // (try 'msi-kbd --help' for options and settings or see Usage()) 3 | // 4 | // Hal Pomeranz (hal@deer-run.com), Deer Run Associates, 2015-04-08 5 | // This code released under Creative Commons Attribution license (CC BY) 6 | 7 | var keyboard = require('msi-keyboard')(); 8 | var argv = require('minimist')(process.argv.slice(2), { 9 | string: 'clmrM'.split(''), 10 | unknown: Usage 11 | }); 12 | 13 | var colors = [ 14 | 'black', 15 | 'red', 16 | 'orange', 17 | 'yellow', 18 | 'green', 19 | 'cyan', 20 | 'blue', 21 | 'purple', 22 | 'white' 23 | ]; 24 | var intensities = ['light', 'low', 'med', 'high']; 25 | var modes = ['normal', 'gaming', 'breathe', 'demo', 'wave']; 26 | 27 | if (Object.keys(argv).length < 2) { 28 | return Usage(); 29 | } 30 | 31 | if (argv.c) { 32 | LightKbd('left', argv.c); 33 | LightKbd('middle', argv.c); 34 | LightKbd('right', argv.c); 35 | } 36 | 37 | if (argv.l) { 38 | LightKbd('left', argv.l); 39 | } 40 | 41 | if (argv.m) { 42 | LightKbd('middle', argv.m); 43 | } 44 | 45 | if (argv.r) { 46 | LightKbd('right', argv.r); 47 | } 48 | 49 | if (argv.M) { 50 | if (modes.indexOf(argv.M.toLowerCase()) > -1) { 51 | keyboard.mode(argv.M); 52 | } 53 | else { 54 | Usage('Unrecognized mode ' + argv.M); 55 | } 56 | } 57 | 58 | function LightKbd(region, colorstr) { 59 | colorstr = colorstr.toLowerCase(); 60 | 61 | var colorSet = ''; 62 | var intenSet = 'high'; 63 | var colorargs = colorstr.split(':'); 64 | 65 | for (i = 0; i < colorargs.length; i++) { 66 | if (colorargs[i] === 'none') { 67 | colorargs[i] = 'black'; 68 | } 69 | if (colors.indexOf(colorargs[i]) > -1) { 70 | colorSet = colorargs[i]; 71 | } 72 | else if (intensities.indexOf(colorargs[i]) > -1) { 73 | intenSet = colorargs[i]; 74 | } 75 | else { 76 | Usage('Unrecognized color spec ' + colorargs[i] + ' for ' + region + ' region'); 77 | } 78 | } 79 | 80 | if (!colorSet.length) { 81 | return Usage('You must specify a color for ' + region + ' region'); 82 | } 83 | 84 | keyboard.color(region, {color:colorSet, intensity:intenSet}); 85 | } 86 | 87 | 88 | function Usage(msg) { 89 | if (msg.indexOf('-') !== 0) { 90 | process.stderr.write(msg + '\n'); 91 | } 92 | process.stderr.write('Usage: msi-kbd [-C colorspec | -l colorspec -m colorspec -r colorspec] [-M mode]\n'); 93 | process.stderr.write(' Colorspec should be color:intensity\n'); 94 | process.stderr.write(' Valid colors: ' + colors.join(', ') + '\n'); 95 | process.stderr.write(' Valid intensities: ' + intensities.join(', ') + '\n'); 96 | process.stderr.write(' Valid modes: ' + modes.join(', ') + '\n'); 97 | process.stderr.write('sudo node msi-kbd.js -C blue -l green -r red:high' + '\n'); 98 | process.exit(1); 99 | } 100 | -------------------------------------------------------------------------------- /lib/findKeyboard.js: -------------------------------------------------------------------------------- 1 | var hid = require('node-hid'); 2 | var setColor = require('./setColor'); 3 | var setMode = require('./setMode'); 4 | var constants = require('./constants'); 5 | var nodeColor = require('color'); 6 | 7 | hid.setDriverType('libusb'); 8 | 9 | module.exports = function() { 10 | var board = new hid.HID(6000, 65280); 11 | board.current = {}; 12 | 13 | board.color = function(region, obj) { 14 | if (typeof obj === 'string') obj = {color: nodeColor(obj)}; 15 | if (typeof obj.color === 'string') obj.color = nodeColor(obj.color); 16 | return setColor(board, region, obj.color, obj.intensity); 17 | }; 18 | 19 | board.mode = function(mode, left, middle, right, period) { 20 | 21 | /** 22 | * One color parameter; set it as the 23 | * primary color for all areas, leavings 24 | * secondary black 25 | */ 26 | if (arguments.length == 2) { 27 | 28 | left = left; 29 | middle = left; 30 | right = left; 31 | 32 | /** 33 | * Two color parameters; set them as 34 | * the primary and secondary colors 35 | * for all areas. 36 | */ 37 | } else if (arguments.length == 3) { 38 | 39 | if ((typeof left === 'string' || typeof left === 'number') && 40 | (typeof middle === 'string' || typeof middle === 'number')) { 41 | 42 | var primary = left; 43 | var secondary = middle; 44 | left = {primary: primary, secondary: secondary}; 45 | middle = {primary: primary, secondary: secondary}; 46 | right = {primary: primary, secondary: secondary}; 47 | 48 | } 49 | } 50 | 51 | setMode(board, mode, left, middle, right, period); 52 | return board; 53 | }; 54 | board.blink = function(regions, time){ 55 | if (!Array.isArray(regions)) { 56 | time = regions; 57 | regions = Object.keys(constants.regions); 58 | } 59 | if (typeof time === 'undefined') time = 1000; 60 | board._blinks = {}; 61 | 62 | regions.forEach(function(region){ 63 | var startColor = board.current[region]; 64 | if (!startColor) return; 65 | 66 | 67 | var interval = setInterval(function(){ 68 | board.blinkRegion(region, startColor, time/2); 69 | }, time); 70 | 71 | board._blinks[region] = { 72 | interval: interval, 73 | color: startColor 74 | }; 75 | }); 76 | return board; 77 | }; 78 | 79 | board.stopBlink = function(){ 80 | Object.keys(board._blinks).forEach(function(region){ 81 | var blink = board._blinks[region]; 82 | clearInterval(blink.interval); 83 | board.color(region, blink.color); 84 | }); 85 | return board; 86 | }; 87 | 88 | board.blinkRegion = function(region, color, time) { 89 | board.color(region, 'black'); 90 | 91 | setTimeout(function(){ 92 | board.color(region, color); 93 | }, time); 94 | 95 | return board; 96 | }; 97 | 98 | return board; 99 | } 100 | -------------------------------------------------------------------------------- /lib/setMode.js: -------------------------------------------------------------------------------- 1 | var constants = require ('./constants'); 2 | 3 | module.exports = function (keyboard, mode, regions, period){ 4 | if (!mode) mode = 'normal'; 5 | if (typeof constants.modes[mode] === 'undefined') throw 'invalid mode'; 6 | 7 | if (mode == 'wave' || mode == 'breathe') { 8 | if (period === undefined || typeof period !== 'number') { 9 | period = 2; 10 | } 11 | 12 | if (typeof regions === 'undefined') 13 | regions = 'blue'; 14 | 15 | if (typeof regions !== 'object') 16 | regions = { left: regions, middle: regions, right: regions }; 17 | 18 | /* 19 | * NOTES about period valies: 20 | * The period paramaters are how long (in seconds?) it will take each of the RGB 21 | * components of each keyboard area to complete a cycle. Setting them different 22 | * from each other creates an interesting effect, but not something I want to 23 | * support at the moment. 24 | * The total time to change the color of the area is the longest of the three period 25 | * values for an area. 26 | * 27 | * In breathe mode (area colors changing in parallel), the duration of the breathe 28 | * loop is the longest period of all three areas. 29 | * Each area will reach the peak of its primary and secondary colors in sync. 30 | * If one area is set to be much quicker than the others, you will see it turn 31 | * its primary color quickly and stay fully lit while the other two catch up, 32 | * then the quick area will quickly change to the secondary color and stay solid 33 | * ntil the other two catch up again, and so on. 34 | * 35 | * In wave mode (area colors changing in sequence), the duration of the wave loop 36 | * is the sum of the longest period in each area. 37 | * The keyboard will start with each area in its secondary color. The left area 38 | * will begin changing first, taking (period/2) seconds to reach full primary color. 39 | * At that point, it will start to fade back to its secondary color while the middle 40 | * section begins its transition to its primary color. This continues left-to-right 41 | * across the keyboard, and then starts over with the left fading to primary as the 42 | * right side fade back to secondary. 43 | * If you don't sync up the total period duration for each of the areas, some areas 44 | * will change faster than others. If the left area hasn't yet reached its peak 45 | * secondary color by time the right side hits its primary peak (signally the left 46 | * area's turn to fade to primary), the hardware realizes it has fallen behind and 47 | * stops the wave until the user issues the comand again. 48 | */ 49 | 50 | var _regions = ['left', 'middle', 'right']; 51 | var Def = null; 52 | for(var k in _regions) { 53 | var _k = parseInt(k) *3; 54 | if (typeof regions[_regions[k]] !== 'undefined') { 55 | Def = getSettingsForRegion (regions[_regions[k]], _regions[k]); 56 | sendData (keyboard, _k + 1, Def.primary.color, Def.primary.level, 0); 57 | sendData (keyboard, _k + 2, Def.secondary.color, Def.secondary.level, 0); 58 | sendData (keyboard, _k + 3, period, period, period); 59 | } else { 60 | sendData (keyboard, _k + 1, 'black', 0, 0); 61 | sendData (keyboard, _k + 2, 'black', 0, 0); 62 | sendData (keyboard, _k + 3, period, period, period); 63 | } 64 | } 65 | } 66 | 67 | //Initalize the mode 68 | commit (keyboard, constants.modes[mode]); 69 | 70 | //Save the mode for reference 71 | keyboard.currentMode = mode; 72 | 73 | return keyboard; 74 | }; 75 | 76 | function getSettingsForRegion (data, region) { 77 | var regionDef = null; 78 | 79 | switch (typeof data) { 80 | 81 | case 'string': 82 | if (typeof constants.colors[data] === 'undefined') 83 | throw 'invalid color for ' + region + ' region'; 84 | 85 | regionDef = { 86 | primary: {color: constants.colors[data], level: 0}, 87 | secondary: {color: constants.colors['black'], level: 0} 88 | }; 89 | break; 90 | 91 | case 'number': 92 | if (data < 0 || data >= constants.colors.length) 93 | throw 'invalid color for ' + region + ' region'; 94 | 95 | regionDef = { 96 | primary: {color: data, level: 0}, 97 | secondary: {color: constants.colors['black'], level: 0} 98 | }; 99 | 100 | case 'object': 101 | if (data.primary) 102 | regionDef = {primary: getColorIntensityLevel (data.primary, region, true)}; 103 | else 104 | regionDef = {primary: getColorIntensityLevel (data, region, true)}; 105 | 106 | if (data.secondary) { 107 | 108 | regionDef.secondary = getColorIntensityLevel (data.secondary, region); 109 | 110 | //Default to black if both settings are unset 111 | if (regionDef.secondary.color < 0 && regionDef.secondary.level < 0) 112 | regionDef.secondary = {color: constants.colors['black'], level: 0}; 113 | 114 | //Default to primary settings if either are unset 115 | if (regionDef.secondary.color < 0) 116 | regionDef.secondary.color = regionDef.primary.color; 117 | 118 | if (regionDef.secondary.level < 0) 119 | regionDef.secondary.level = regionDef.primary.level; 120 | 121 | } else { 122 | //Default secondary to black if unset 123 | regionDef.secondary = {color: constants.colors['black'], level: 0}; 124 | } 125 | break; 126 | 127 | default: 128 | throw 'invalid color for ' + region + ' region'; 129 | break; 130 | } 131 | 132 | return regionDef; 133 | } 134 | 135 | function getColorIntensityLevel (data, region, isRequired) { 136 | var colorName, levelName; 137 | var colorId = -1, levelId = -1; 138 | 139 | switch (typeof data) { 140 | 141 | case 'string': 142 | colorName = data; 143 | break; 144 | 145 | case 'number': 146 | colorId = data; 147 | break; 148 | 149 | default: 150 | if (typeof data.color === 'string') 151 | colorName = data.color; 152 | else if (typeof data.color === 'number') 153 | colorId = data.color; 154 | break; 155 | } 156 | 157 | if (colorName) { 158 | if (typeof constants.colors[colorName] === 'undefined') 159 | throw 'invalid color for ' + region + ' region'; 160 | colorId = constants.colors[colorName]; 161 | } 162 | 163 | //Always invalid if color is above range. colorId < 0 should be allowed if the fields are not required 164 | if (colorId >= constants.colors.length || (isRequired && colorId < 0)) 165 | throw 'invalid color for ' + region + ' region'; 166 | 167 | if (data.intensity) { 168 | if (typeof data.intensity === 'string') 169 | levelName = data.intensity; 170 | else if (typeof data.intensity === 'number') 171 | levelId = data.intensity; 172 | } 173 | 174 | if (levelName) { 175 | if (typeof constants.levels[levelName] === 'undefined') 176 | throw 'invalid intensity for ' + region + ' region'; 177 | levelId = constants.levels[levelName]; 178 | } 179 | 180 | if (levelId >= constants.colors.length) 181 | throw 'invalid intensity for ' + region + ' region'; 182 | 183 | if (isRequired && levelId < 0) 184 | levelId = 0; 185 | 186 | colorDef = {color: colorId, level: levelId}; 187 | 188 | return colorDef; 189 | } 190 | 191 | function sendData (keyboard, val1, val2, val3, val4) { 192 | var data = []; 193 | 194 | data[0] = 1; 195 | data[1] = 2; 196 | data[2] = 67; 197 | data[3] = val1; 198 | data[4] = val2; 199 | data[5] = val3; 200 | data[6] = val4; 201 | data[7] = 236; 202 | 203 | keyboard.sendFeatureReport (data); 204 | } 205 | 206 | function commit (keyboard, mode) { 207 | var data = []; 208 | 209 | data[0] = 1; 210 | data[1] = 2; 211 | data[2] = 65; 212 | data[3] = mode; 213 | data[4] = 0; 214 | data[5] = 0; 215 | data[6] = 0; 216 | data[7] = 236; 217 | 218 | keyboard.sendFeatureReport (data); 219 | } 220 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MSI Keyboard LED Controller 2 | 3 | > OS independent* LED Controller for MSI Steelseries laptop keyboards Using Node.js 4 | 5 | [![NPM version](https://badge.fury.io/js/msi-keyboard.png)](http://badge.fury.io/js/msi-keyboard) 6 | 7 | ## Information 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
Packagemsi-keyboard
DescriptionMSI Keyboard LED Controller
HardwareMSI GE, GT Steelseries Keyboard
Node Version>= 0.4
26 | 27 | ![keyboard](https://i.cloudup.com/V7zz0ZdHT8.png) 28 | 29 | ### [Looking for a GUI application?](https://github.com/stevelacy/msi-keyboard-gui) 30 | 31 | ## Usage 32 | 33 | Make sure you have the needed usb lib requirements for your OS. 34 | 35 | This project now supports full RGB/hex colors. 36 | 37 | Generic Linux: `libusb-dev` `libusb-1.0-0-dev` 38 | 39 | #### Use it as command line : 40 | https://github.com/Kwaadpepper/msi-keyboard-CLI 41 | 42 | #### if using as a stand alone module: 43 | 44 | `npm install` 45 | 46 | ### Note: 47 | Linux and *nix systems may require sudo to access the hid device interface. 48 | 49 | *Not tested on all platforms. 50 | Platform tests appreciated 51 | 52 | 53 | ```javascript 54 | // require the LED module 55 | var keyboard = require('msi-keyboard')(); 56 | 57 | // Set left region to high intensity, color red 58 | keyboard.color('left', { 59 | color: 'red', 60 | intensity: 'high' 61 | }); 62 | 63 | // Set middle region to green default high intensity 64 | keyboard.color('middle', 'green'); 65 | 66 | 67 | // Set right region to blue with light intensity 68 | keyboard.color('right', { 69 | color: 'blue', 70 | intensity: 'light', 71 | }); 72 | 73 | 74 | // Hardware modes 75 | // Setting .color() will Not affect the hardware defined colors for modes 76 | 77 | // Set Hardware mode to breath 78 | keyboard.mode('breathe', 'green'); 79 | 80 | 81 | // Blinking 82 | // Set the keyboard.color() Before calling .blink() 83 | // Refer to examples/blinkMulti.js 84 | 85 | // Blink all the keyboard LEDs to 750ms 86 | keyboard.blink(750); 87 | 88 | 89 | // Blink Only left and right regions at 750ms 90 | keyboard.blink(['left','right'], 750); 91 | 92 | 93 | // Use the default blink, time: 1000ms 94 | keyboard.blink(); 95 | 96 | 97 | // Stop the blink after 5000ms 98 | setTimeout(keyboard.stopBlink, 5000); 99 | 100 | ``` 101 | 102 | 103 | 104 | ## Colors 105 | `keyboard.colors(String region, String Color);` 106 | 107 | Colors must be set before using keyboard.blink(); 108 | 109 | They will not affect hardware-default modes such as Wave and Breathing. 110 | 111 | All colors supported by [Colors.js](https://github.com/Marak/colors.js) are now supported here 112 | 113 | To set a color use keyboard.colors() There are two ways to set the color to a region: 114 | ```javascript 115 | keyboard.color('middle', 'green'); 116 | keyboard.color('middle', {color:'#ffffff', intensity:'high'}); 117 | keyboard.color('middle', {color:'#4654BD', intensity:'high'}); 118 | ``` 119 | 120 | 121 | ## Intensity 122 | `keyboard.colors(String region, {String color, String intensity});` 123 | 124 | The color intensity to white can be set via keyboard.colors(); 125 | 126 | The following intensities are used: 127 | 128 | light 129 | low 130 | med 131 | high 132 | 133 | To set it: 134 | 135 | ```javascript 136 | keyboard.color('right', { 137 | color: '#1CA626', 138 | intensity: 'med', // light, low, med, high 139 | }); 140 | ``` 141 | 142 | ##Modes 143 | `keyboard.mode(String mode, String primaryColor, String secondaryColor);` 144 | `keyboard.mode(String mode, Object left, Object middle, Object right, Integer cyclePeriod);` 145 | 146 | MSI Steelseries keyboards have built modes. 147 | 148 | Breathe and Wave modes support fading between colors, which can be set when calling the keyboard.mode() method. 149 | 150 | Passing in only one color argument defaults the secondaryColor to 'black': 151 | 152 | `keyboard.mode(String mode, String primaryColor);` 153 | 154 | You can also set each region's color individually: 155 | 156 | `keyboard.mode(String mode, String leftPrimary, String middlePrimary, String rightPrimary, Integer cyclePeriod);` 157 | 158 | `keyboard.mode(String mode, Object left, Object middle, Object right, Integer cyclePeriod);` 159 | 160 | Region objects are defined as such: 161 | 162 | right: { 163 | primary: { 164 | color: 'red', 165 | intensity: 'high' 166 | }, 167 | secondary: { 168 | color: 'blue', 169 | intensity: 'high' 170 | } 171 | } 172 | 173 | Which is equivalent to: 174 | 175 | right: { 176 | color: 'red', 177 | intensity: 'high', 178 | secondary: { 179 | color: 'blue', 180 | intensity: 'high' 181 | } 182 | } 183 | 184 | 185 | You can also define just the primary and secondary colors, leaving the intensities to their default (high): 186 | 187 | right: { 188 | primary: 'red', 189 | secondary: 'blue' 190 | } 191 | 192 | If you specify the color and intensity directly in the Region object, you can set just one of the secondary fields and the other will take the default from the primary (secondary color will be red with light intensity): 193 | 194 | right: { 195 | color: 'red', 196 | intensity: 'high', 197 | secondary: {intensity:'light'} 198 | } 199 | 200 | The cyclePeriod defaults to 2 seconds when not passed in. 201 | 202 | The modes defined by the hardware are: 203 | 204 | Normal 205 | Gaming 206 | Breathe 207 | Demo 208 | Wave 209 | 210 | 211 | Usage: 212 | 213 | ```javascript 214 | 215 | keyboard.mode('breathe', 'green', 'red', 'yellow'); 216 | 217 | ``` 218 | 219 | 220 | ##Regions 221 | `keyboard.colors(String region, String color);` 222 | 223 | There are three regions on the Steelseries keyboard: 224 | 225 | Left 226 | Middle 227 | Right 228 | 229 | Each can have a color and intensity set. 230 | 231 | 232 | 233 | ##Blink 234 | `keyboard.blink(Time milliseconds);` 235 | 236 | The time is the speed in which the keyboard is to blink. 237 | 238 | keyboard.colors(); Must be set before using keyboard.blink(); 239 | 240 | Usage: 241 | 242 | ```javascript 243 | // keyboard.color(...); 244 | 245 | 246 | keyboard.blink(750); 247 | ``` 248 | 249 | To blink one, or two regions only: 250 | 251 | ```javascript 252 | // keyboard.color(...); 253 | 254 | 255 | keyboard.blink(['left','right'], 750); 256 | ``` 257 | 258 | 259 | 260 | ## Examples 261 | 262 | You can view more examples in the [example folder.](https://github.com/wearefractal/msi-keyboard/tree/master/examples) 263 | 264 | ### Confirmed Systems 265 | 266 | ```sh 267 | OS: Debain 8 268 | Kernel: Linux 4.4.0 AMD 269 | Node: v5 / v6 270 | libusb-dev: v0.1.12 271 | 272 | --- 273 | 274 | OS: Arch Linux 275 | Kernel: 4.5.1-1-ARCH 276 | Node: v6.0.0 277 | libusb v0.1.12 278 | 279 | 280 | --- 281 | 282 | OS: Ubuntu 16.04 283 | Kernel: 4.4.14 284 | Node: v6 285 | libusb v0.1.12 286 | ``` 287 | 288 | ## LICENSE 289 | 290 | (MIT License) 291 | 292 | Copyright (c) 2013 | Steve Lacy (http://slacy.me) 293 | 294 | Permission is hereby granted, free of charge, to any person obtaining 295 | a copy of this software and associated documentation files (the 296 | "Software"), to deal in the Software without restriction, including 297 | without limitation the rights to use, copy, modify, merge, publish, 298 | distribute, sublicense, and/or sell copies of the Software, and to 299 | permit persons to whom the Software is furnished to do so, subject to 300 | the following conditions: 301 | 302 | The above copyright notice and this permission notice shall be 303 | included in all copies or substantial portions of the Software. 304 | 305 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 306 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 307 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 308 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 309 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 310 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 311 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 312 | --------------------------------------------------------------------------------