├── Massdrop ├── Alt-Keymaps.7z └── Massdrop_CTRL_QMK_Keyboard.js ├── README.md ├── YMDK └── YMDK_YMD09_QMK_Keyboard.js ├── Framework └── Framework_Macropad.js ├── XBows └── XBows_KnightPlus_QMK_ANSI_Numpad.js ├── Keychron ├── Q Series │ ├── Plus │ │ └── Keychron_Q0_Plus_QMK_ANSI_Keyboard.js │ ├── Pro │ │ ├── Keychron_Q2_Pro_QMK_ANSI_Keyboard.js │ │ └── Keychron_Q8_Pro_QMK_ANSI_Keyboard.js │ ├── Max │ │ └── Keychron_Q8_Max_QMK_ANSI_Keyboard.js │ └── Standard │ │ └── Keychron_Q0_QMK_ANSI_Keyboard.js ├── K Series │ └── Pro │ │ ├── Keychron_K12_Pro_QMK_ANSI_Keyboard.js │ │ └── Keychron_K6_Pro_ANSI_Keyboard.js └── V Series │ └── Standard │ ├── Keychron_V4_QMK_ANSI_Keyboard.js │ ├── Keychron_V4_QMK_ISO_Keyboard.js │ └── Keychron_V2_QMK_ANSI_Keyboard.js ├── Ergodox_EZ └── Ergodox_EZ_Glow_QMK.js ├── GMMK └── GMMK_Numpad_QMK.js ├── Monsgeek └── Monsgeek_M7_QMK_ANSI_Keyboard.js ├── Swagkeys └── SW_EAVE65.js ├── DZTech ├── DZTech-60RGB_Keyboard.js └── DZTech-65RGB-V3_Keyboard.js └── KBDFans └── KBDFans_KBD67_V2_QMK_ISO_Keyboard.js /Massdrop/Alt-Keymaps.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SRGBmods/qmk-plugins/HEAD/Massdrop/Alt-Keymaps.7z -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QMK + SRGB Support - [a Reddit post is found here](https://www.reddit.com/r/SignalRGB/comments/1gg4s1z/qmk_support_madness_partnerships_were_willing_to/) # 2 | 3 | **One thing of note, if you are attempting to use VIA or Vial to configure your keyboard, is you _must_ quit SignalRGB before running either software. This is a limitation of the raw_hid_send that both VIA and SignalRGB use to talk to your keyboard!** 4 | 5 | ## Here you will find plugins for QMK keyboards to work with SignalRGB ## 6 | 7 | ### Please note you must be using QMK firmware with SignalRGB Protocol support added to it to use these plugins ### 8 | [More information available here.](https://docs.signalrgb.com/qmk) 9 | 10 | [![Click here to add this repo to SignalRGB](https://raw.githubusercontent.com/SRGBmods/QMK-Images/main/images/add-to-signalrgb.png)](https://srgbmods.net/s?p=addon/install?url=https://github.com/SRGBmods/qmk-plugins) 11 | 12 | Using the above button will help keep your plugins up to date whenever any changes are made to them. (Added by Default to SignalRGB releases now!) 13 | 14 | Tech support is available on the [Test Plugin Discord](https://discord.com/invite/J5dwtcNhqC) with the QMK #roles (join #roles and pick the QMK to gain access to the QMK channels!) 15 | 16 | ### Needs Testing ### 17 | Please see the [\_Needs-Testing](https://github.com/SRGBmods/qmk-plugins/tree/needs-testing) branch if you find your keyboard in there and it works. Please let us know either via the Discord link above or with the Issues system here on GitHub, and thanks for the help! 18 | 19 | ### Supported Devices ### 20 | Browse the manufacturer directories here. The list was getting too large to maintain on top of maintaining everything else. 21 | -------------------------------------------------------------------------------- /YMDK/YMDK_YMD09_QMK_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "YMDK YMD09 QMK Keyboard"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x594d; } 4 | export function ProductId() { return 0x4409; } 5 | export function Publisher() { return "Shie1dsey"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [3, 3]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() { 18 | return [ 19 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 20 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#000000"}, 21 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 22 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 23 | ]; 24 | } 25 | 26 | //Plugin Version: Built for Protocol V1.0.6 27 | 28 | const vKeyNames = [ 29 | "FN_MO13", "FN_MO23", "Del", //3 30 | "Esc", "Up Arrow", "Enter", //3 31 | "Left Arrow", "Down Arrow", "Right Arrow", //3 32 | ]; 33 | 34 | const vKeys = [ 35 | 0, 1, 2, //3 36 | 3, 4, 5, //3 37 | 6, 7, 8, //3 38 | ]; 39 | 40 | const vKeyPositions = [ 41 | [0, 0], [1, 0], [2, 0], //3 42 | [0, 1], [1, 1], [2, 1], //3 43 | [0, 2], [1, 2], [2, 2], //3 44 | ]; 45 | 46 | let LEDCount = 0; 47 | let IsViaKeyboard = false; 48 | const MainlineQMKFirmware = 1; 49 | const VIAFirmware = 2; 50 | const PluginProtocolVersion = "1.0.6"; 51 | 52 | export function LedNames() { 53 | return vKeyNames; 54 | } 55 | 56 | export function LedPositions() { 57 | return vKeyPositions; 58 | } 59 | 60 | export function vKeysArrayCount() { 61 | device.log('vKeys ' + vKeys.length); 62 | device.log('vKeyNames ' + vKeyNames.length); 63 | device.log('vKeyPositions ' + vKeyPositions.length); 64 | } 65 | 66 | export function Initialize() { 67 | requestFirmwareType(); 68 | requestQMKVersion(); 69 | requestSignalRGBProtocolVersion(); 70 | requestUniqueIdentifier(); 71 | requestTotalLeds(); 72 | effectEnable(); 73 | 74 | } 75 | 76 | export function Render() { 77 | sendColors(); 78 | } 79 | 80 | export function Shutdown(SystemSuspending) { 81 | 82 | if(SystemSuspending) { 83 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 84 | } else { 85 | if (shutdownMode === "SignalRGB") { 86 | sendColors(shutdownColor); 87 | } else { 88 | effectDisable(); 89 | } 90 | } 91 | 92 | //vKeysArrayCount(); // For debugging array counts 93 | 94 | } 95 | 96 | function commandHandler() { 97 | const readCounts = []; 98 | 99 | do { 100 | const returnpacket = device.read([0x00], 32, 10); 101 | processCommands(returnpacket); 102 | 103 | readCounts.push(device.getLastReadSize()); 104 | 105 | // Extra Read to throw away empty packets from Via 106 | // Via always sends a second packet with the same Command Id. 107 | if(IsViaKeyboard) { 108 | device.read([0x00], 32, 10); 109 | } 110 | } 111 | while(device.getLastReadSize() > 0); 112 | 113 | } 114 | 115 | function processCommands(data) { 116 | switch(data[1]) { 117 | case 0x21: 118 | returnQMKVersion(data); 119 | break; 120 | case 0x22: 121 | returnSignalRGBProtocolVersion(data); 122 | break; 123 | case 0x23: 124 | returnUniqueIdentifier(data); 125 | break; 126 | case 0x24: 127 | sendColors(); 128 | break; 129 | case 0x27: 130 | returnTotalLeds(data); 131 | break; 132 | case 0x28: 133 | returnFirmwareType(data); 134 | break; 135 | } 136 | } 137 | 138 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 139 | { 140 | device.write([0x00, 0x21], 32); 141 | device.pause(30); 142 | commandHandler(); 143 | } 144 | 145 | function returnQMKVersion(data) { 146 | const QMKVersionByte1 = data[2]; 147 | const QMKVersionByte2 = data[3]; 148 | const QMKVersionByte3 = data[4]; 149 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 150 | device.log("QMK SRGB Plugin Version: "+ Version()); 151 | device.pause(30); 152 | } 153 | 154 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 155 | { 156 | device.write([0x00, 0x22], 32); 157 | device.pause(30); 158 | commandHandler(); 159 | } 160 | 161 | function returnSignalRGBProtocolVersion(data) { 162 | const ProtocolVersionByte1 = data[2]; 163 | const ProtocolVersionByte2 = data[3]; 164 | const ProtocolVersionByte3 = data[4]; 165 | 166 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 167 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 168 | 169 | 170 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) { 171 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 172 | } 173 | 174 | device.pause(30); 175 | } 176 | 177 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 178 | { 179 | if(device.write([0x00, 0x23], 32) === -1) { 180 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 181 | } 182 | 183 | device.pause(30); 184 | commandHandler(); 185 | } 186 | 187 | 188 | function returnUniqueIdentifier(data) { 189 | const UniqueIdentifierByte1 = data[2]; 190 | const UniqueIdentifierByte2 = data[3]; 191 | const UniqueIdentifierByte3 = data[4]; 192 | 193 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) { 194 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 195 | } 196 | 197 | device.pause(30); 198 | } 199 | 200 | function requestTotalLeds() //Calculate total number of LEDs 201 | { 202 | device.write([0x00, 0x27], 32); 203 | device.pause(30); 204 | commandHandler(); 205 | } 206 | 207 | function returnTotalLeds(data) { 208 | LEDCount = data[2]; 209 | device.log("Device Total LED Count: " + LEDCount); 210 | device.pause(30); 211 | } 212 | 213 | function requestFirmwareType() { 214 | device.write([0x00, 0x28], 32); 215 | device.pause(30); 216 | commandHandler(); 217 | } 218 | 219 | function returnFirmwareType(data) { 220 | const FirmwareTypeByte = data[2]; 221 | 222 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) { 223 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 224 | } 225 | 226 | if(FirmwareTypeByte === MainlineQMKFirmware) { 227 | IsViaKeyboard = false; 228 | device.log("Firmware Type: Mainline"); 229 | } 230 | 231 | if(FirmwareTypeByte === VIAFirmware) { 232 | IsViaKeyboard = true; 233 | device.log("Firmware Type: VIA"); 234 | } 235 | 236 | device.pause(30); 237 | } 238 | 239 | function effectEnable() //Enable the SignalRGB Effect Mode 240 | { 241 | device.write([0x00, 0x25], 32); 242 | device.pause(30); 243 | } 244 | 245 | function effectDisable() //Revert to Hardware Mode 246 | { 247 | device.write([0x00, 0x26], 32); 248 | device.pause(30); 249 | } 250 | 251 | function createSolidColorArray(color) { 252 | const rgbdata = new Array(vKeys.length * 3).fill(0); 253 | 254 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 255 | const iLedIdx = vKeys[iIdx] * 3; 256 | rgbdata[iLedIdx] = color[0]; 257 | rgbdata[iLedIdx+1] = color[1]; 258 | rgbdata[iLedIdx+2] = color[2]; 259 | } 260 | 261 | return rgbdata; 262 | } 263 | 264 | function grabColors(overrideColor) { 265 | 266 | if(overrideColor) { 267 | return createSolidColorArray(hexToRgb(overrideColor)); 268 | } else if (LightingMode === "Forced") { 269 | return createSolidColorArray(hexToRgb(forcedColor)); 270 | } 271 | 272 | const rgbdata = new Array(vKeys.length * 3).fill(0); 273 | 274 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 275 | const iPxX = vKeyPositions[iIdx][0]; 276 | const iPxY = vKeyPositions[iIdx][1]; 277 | const color = device.color(iPxX, iPxY); 278 | 279 | const iLedIdx = vKeys[iIdx] * 3; 280 | rgbdata[iLedIdx] = color[0]; 281 | rgbdata[iLedIdx+1] = color[1]; 282 | rgbdata[iLedIdx+2] = color[2]; 283 | } 284 | 285 | return rgbdata; 286 | } 287 | 288 | function sendColors(overrideColor) { 289 | const rgbdata = grabColors(overrideColor); 290 | 291 | const LedsPerPacket = 9; 292 | let BytesSent = 0; 293 | let BytesLeft = rgbdata.length; 294 | 295 | while(BytesLeft > 0) { 296 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 297 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 298 | 299 | BytesLeft -= BytesToSend; 300 | BytesSent += BytesToSend; 301 | } 302 | } 303 | 304 | function StreamLightingData(StartLedIdx, RGBData) { 305 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 306 | device.write(packet, 33); 307 | } 308 | 309 | function hexToRgb(hex) { 310 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 311 | const colors = []; 312 | colors[0] = parseInt(result[1], 16); 313 | colors[1] = parseInt(result[2], 16); 314 | colors[2] = parseInt(result[3], 16); 315 | 316 | return colors; 317 | } 318 | 319 | export function Validate(endpoint) { 320 | return endpoint.interface === 1; 321 | } 322 | 323 | export function ImageUrl() 324 | { 325 | return "https://raw.githubusercontent.com/SRGBmods/QMK-Images/main/images/YMDK_YMD09.png"; 326 | } -------------------------------------------------------------------------------- /Framework/Framework_Macropad.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "Laptop 16 RGB Macropad"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x32AC; } 4 | export function ProductId() { return 0x0013; } 5 | export function Publisher() { return "WhirlwindFX"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard";} 8 | export function Size() { return [4, 6]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() { 18 | return [ 19 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 20 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 21 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 22 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 23 | ]; 24 | } 25 | 26 | 27 | //Plugin Version: Built for Protocol V1.0.6 28 | 29 | const vKeys = 30 | [ 31 | 5, 2, 22, 17, 32 | 4, 0, 20, 18, 33 | 7, 1, 21, 16, 34 | 6, 3, 23, 19, 35 | 9, 11, 15, 13, 36 | 8, 10, 14, 12 37 | ]; 38 | 39 | const vKeyNames = 40 | [ 41 | 42 | "Key 1", "Key 2", "Key 3", "Key 4", 43 | "Numlock", "Num /", "Num *", "Num -", 44 | "Num 7", "Num 8", "Num 9", "Num + Upper", 45 | "Num 4", "Num 5", "Num 6", "Num + Lower", 46 | "Num 1", "Num 2", "Num 3", "Num Enter Upper", 47 | "Num 0 L", "Num 0 R", "Num .", "Num Enter Lower" 48 | ]; 49 | 50 | const vKeyPositions = 51 | [ 52 | [0, 0], [1, 0], [2, 0], [3, 0], 53 | [0, 1], [1, 1], [2, 1], [3, 1], 54 | [0, 2], [1, 2], [2, 2], [3, 2], 55 | [0, 3], [1, 3], [2, 3], [3, 3], 56 | [0, 4], [1, 4], [2, 4], [3, 4], 57 | [0, 5], [1, 5], [2, 5], [3, 5] 58 | ]; 59 | 60 | let LEDCount = 0; 61 | let IsViaKeyboard = false; 62 | const MainlineQMKFirmware = 1; 63 | const VIAFirmware = 2; 64 | const PluginProtocolVersion = "1.0.6"; 65 | 66 | export function LedNames() 67 | { 68 | return vKeyNames; 69 | } 70 | 71 | export function LedPositions() 72 | { 73 | return vKeyPositions; 74 | } 75 | 76 | export function vKeysArrayCount() 77 | { 78 | device.log('vKeys ' + vKeys.length); 79 | device.log('vKeyNames ' + vKeyNames.length); 80 | device.log('vKeyPositions ' + vKeyPositions.length); 81 | } 82 | 83 | export function Initialize() 84 | { 85 | requestFirmwareType(); 86 | requestQMKVersion(); 87 | requestSignalRGBProtocolVersion(); 88 | requestUniqueIdentifier(); 89 | requestTotalLeds(); 90 | effectEnable(); 91 | 92 | } 93 | 94 | export function Render() 95 | { 96 | sendColors(); 97 | } 98 | 99 | export function Shutdown(SystemSuspending) 100 | { 101 | 102 | if(SystemSuspending) 103 | { 104 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 105 | } 106 | else 107 | { 108 | if (shutdownMode === "SignalRGB") 109 | { 110 | sendColors(shutdownColor); 111 | } 112 | else 113 | { 114 | effectDisable(); 115 | } 116 | } 117 | //vKeysArrayCount(); // For debugging array counts 118 | 119 | } 120 | 121 | function commandHandler() 122 | { 123 | const readCounts = []; 124 | 125 | do 126 | { 127 | const returnpacket = device.read([0x00], 32, 10); 128 | processCommands(returnpacket); 129 | 130 | readCounts.push(device.getLastReadSize()); 131 | 132 | // Extra Read to throw away empty packets from Via 133 | // Via always sends a second packet with the same Command Id. 134 | if(IsViaKeyboard) 135 | { 136 | device.read([0x00], 32, 10); 137 | } 138 | } 139 | while(device.getLastReadSize() > 0); 140 | 141 | } 142 | 143 | function processCommands(data) 144 | { 145 | switch(data[1]) 146 | { 147 | case 0x21: 148 | returnQMKVersion(data); 149 | break; 150 | case 0x22: 151 | returnSignalRGBProtocolVersion(data); 152 | break; 153 | case 0x23: 154 | returnUniqueIdentifier(data); 155 | break; 156 | case 0x24: 157 | sendColors(); 158 | break; 159 | case 0x27: 160 | returnTotalLeds(data); 161 | break; 162 | case 0x28: 163 | returnFirmwareType(data); 164 | break; 165 | } 166 | } 167 | 168 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 169 | { 170 | device.write([0x00, 0x21], 32); 171 | device.pause(30); 172 | commandHandler(); 173 | } 174 | 175 | function returnQMKVersion(data) 176 | { 177 | const QMKVersionByte1 = data[2]; 178 | const QMKVersionByte2 = data[3]; 179 | const QMKVersionByte3 = data[4]; 180 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 181 | device.log("QMK SRGB Plugin Version: "+ Version()); 182 | device.pause(30); 183 | } 184 | 185 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 186 | { 187 | device.write([0x00, 0x22], 32); 188 | device.pause(30); 189 | commandHandler(); 190 | } 191 | 192 | function returnSignalRGBProtocolVersion(data) 193 | { 194 | const ProtocolVersionByte1 = data[2]; 195 | const ProtocolVersionByte2 = data[3]; 196 | const ProtocolVersionByte3 = data[4]; 197 | 198 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 199 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 200 | 201 | 202 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) 203 | { 204 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 205 | } 206 | 207 | device.pause(30); 208 | } 209 | 210 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 211 | { 212 | if(device.write([0x00, 0x23], 32) === -1) 213 | { 214 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 215 | } 216 | 217 | device.pause(30); 218 | commandHandler(); 219 | } 220 | 221 | 222 | function returnUniqueIdentifier(data) 223 | { 224 | const UniqueIdentifierByte1 = data[2]; 225 | const UniqueIdentifierByte2 = data[3]; 226 | const UniqueIdentifierByte3 = data[4]; 227 | 228 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) 229 | { 230 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 231 | } 232 | 233 | device.pause(30); 234 | } 235 | 236 | function requestTotalLeds() //Calculate total number of LEDs 237 | { 238 | device.write([0x00, 0x27], 32); 239 | device.pause(30); 240 | commandHandler(); 241 | } 242 | 243 | function returnTotalLeds(data) 244 | { 245 | LEDCount = data[2]; 246 | device.log("Device Total LED Count: " + LEDCount); 247 | device.pause(30); 248 | } 249 | 250 | function requestFirmwareType() 251 | { 252 | device.write([0x00, 0x28], 32); 253 | device.pause(30); 254 | commandHandler(); 255 | } 256 | 257 | function returnFirmwareType(data) 258 | { 259 | const FirmwareTypeByte = data[2]; 260 | 261 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) 262 | { 263 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 264 | } 265 | 266 | if(FirmwareTypeByte === MainlineQMKFirmware) 267 | { 268 | IsViaKeyboard = false; 269 | device.log("Firmware Type: Mainline"); 270 | } 271 | 272 | if(FirmwareTypeByte === VIAFirmware) 273 | { 274 | IsViaKeyboard = true; 275 | device.log("Firmware Type: VIA"); 276 | } 277 | 278 | device.pause(30); 279 | } 280 | 281 | function effectEnable() //Enable the SignalRGB Effect Mode 282 | { 283 | device.write([0x00, 0x25], 32); 284 | device.pause(30); 285 | } 286 | 287 | function effectDisable() //Revert to Hardware Mode 288 | { 289 | device.write([0x00, 0x26], 32); 290 | device.pause(30); 291 | } 292 | 293 | function createSolidColorArray(color) 294 | { 295 | const rgbdata = new Array(vKeys.length * 3).fill(0); 296 | 297 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 298 | { 299 | const iLedIdx = vKeys[iIdx] * 3; 300 | rgbdata[iLedIdx] = color[0]; 301 | rgbdata[iLedIdx+1] = color[1]; 302 | rgbdata[iLedIdx+2] = color[2]; 303 | } 304 | 305 | return rgbdata; 306 | } 307 | 308 | function grabColors(overrideColor) 309 | { 310 | if(overrideColor) 311 | { 312 | return createSolidColorArray(hexToRgb(overrideColor)); 313 | } 314 | else if (LightingMode === "Forced") 315 | { 316 | return createSolidColorArray(hexToRgb(forcedColor)); 317 | } 318 | 319 | const rgbdata = new Array(vKeys.length * 3).fill(0); 320 | 321 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 322 | { 323 | const iPxX = vKeyPositions[iIdx][0]; 324 | const iPxY = vKeyPositions[iIdx][1]; 325 | let color = device.color(iPxX, iPxY); 326 | 327 | const iLedIdx = vKeys[iIdx] * 3; 328 | rgbdata[iLedIdx] = color[0]; 329 | rgbdata[iLedIdx+1] = color[1]; 330 | rgbdata[iLedIdx+2] = color[2]; 331 | } 332 | 333 | return rgbdata; 334 | } 335 | 336 | function sendColors(overrideColor) 337 | { 338 | const rgbdata = grabColors(overrideColor); 339 | 340 | const LedsPerPacket = 9; 341 | let BytesSent = 0; 342 | let BytesLeft = rgbdata.length; 343 | 344 | while(BytesLeft > 0) 345 | { 346 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 347 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 348 | 349 | BytesLeft -= BytesToSend; 350 | BytesSent += BytesToSend; 351 | } 352 | } 353 | 354 | function StreamLightingData(StartLedIdx, RGBData) 355 | { 356 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 357 | device.write(packet, 33); 358 | } 359 | 360 | function hexToRgb(hex) 361 | { 362 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 363 | const colors = []; 364 | colors[0] = parseInt(result[1], 16); 365 | colors[1] = parseInt(result[2], 16); 366 | colors[2] = parseInt(result[3], 16); 367 | 368 | return colors; 369 | } 370 | 371 | export function Validate(endpoint) 372 | { 373 | return endpoint.interface === 1; 374 | } 375 | 376 | export function ImageUrl(){ 377 | return "https://marketplace.signalrgb.com/devices/default/misc/usb-drive-render.png"; 378 | } -------------------------------------------------------------------------------- /XBows/XBows_KnightPlus_QMK_ANSI_Numpad.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "XBows KnightPlus Numpad"; } 2 | export function Version() { return "1.1.4"; } 3 | export function VendorId() { return 0x5842; } 4 | export function ProductId() { return 0x4e75; } 5 | export function Publisher() { return "The Larch"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [5, 7]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() 18 | { 19 | return [ 20 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 21 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"000000"}, 22 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 23 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"009bde"}, 24 | ]; 25 | } 26 | 27 | //Plugin Version: Built for Protocol V1.0.6 28 | 29 | const vKeys = 30 | [ 31 | 0, 1, 2, 3, 32 | 4, 5, 6, 7, 33 | 8, 9, 10, 11, 34 | 12, 13, 14, 15, 35 | 16, 17, 18, 19, 36 | 20, 21 37 | ]; 38 | 39 | const vKeyNames = 40 | [ 41 | "Esc", "Tab", "Backspace", "Fn", //What is this a playstation controller? 42 | "Num Lock", "Num /", "Num *", "Num=", 43 | "Num 7", "Num 8", "Num 9", "Num-", 44 | "Num 4", "Num 5", "Num 6", "Num +", 45 | "Num 1", "Num 2", "Num 3", "Num Enter", 46 | "Num 0", "Num ." 47 | ]; 48 | 49 | const vKeyPositions = 50 | [ 51 | [0, 0], [1, 0], [2, 0], [3, 0], 52 | [0, 1], [1, 1], [2, 1], [3, 1], 53 | [0, 2], [1, 2], [2, 2], [3, 2], 54 | [0, 3], [1, 3], [2, 3], [3, 3], 55 | [0, 4], [1, 4], [2, 4], [3, 4], 56 | [0, 5], [2, 5], 57 | ]; 58 | 59 | let LEDCount = 0; 60 | let IsViaKeyboard = false; 61 | const MainlineQMKFirmware = 1; 62 | const VIAFirmware = 2; 63 | const PluginProtocolVersion = "1.0.6"; 64 | 65 | export function LedNames() 66 | { 67 | return vKeyNames; 68 | } 69 | 70 | export function LedPositions() 71 | { 72 | return vKeyPositions; 73 | } 74 | 75 | export function vKeysArrayCount() 76 | { 77 | device.log('vKeys ' + vKeys.length); 78 | device.log('vKeyNames ' + vKeyNames.length); 79 | device.log('vKeyPositions ' + vKeyPositions.length); 80 | } 81 | 82 | export function Initialize() 83 | { 84 | requestFirmwareType(); 85 | requestQMKVersion(); 86 | requestSignalRGBProtocolVersion(); 87 | requestUniqueIdentifier(); 88 | requestTotalLeds(); 89 | effectEnable(); 90 | 91 | } 92 | 93 | export function Render() 94 | { 95 | sendColors(); 96 | } 97 | 98 | export function Shutdown(SystemSuspending) 99 | { 100 | 101 | if(SystemSuspending) 102 | { 103 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 104 | } 105 | else 106 | { 107 | if (shutdownMode === "SignalRGB") 108 | { 109 | sendColors(shutdownColor); 110 | } 111 | else 112 | { 113 | effectDisable(); 114 | } 115 | } 116 | //vKeysArrayCount(); // For debugging array counts 117 | 118 | } 119 | 120 | function commandHandler() 121 | { 122 | const readCounts = []; 123 | 124 | do 125 | { 126 | const returnpacket = device.read([0x00], 32, 10); 127 | processCommands(returnpacket); 128 | 129 | readCounts.push(device.getLastReadSize()); 130 | 131 | // Extra Read to throw away empty packets from Via 132 | // Via always sends a second packet with the same Command Id. 133 | if(IsViaKeyboard) 134 | { 135 | device.read([0x00], 32, 10); 136 | } 137 | } 138 | while(device.getLastReadSize() > 0); 139 | 140 | } 141 | 142 | function processCommands(data) 143 | { 144 | switch(data[1]) 145 | { 146 | case 0x21: 147 | returnQMKVersion(data); 148 | break; 149 | case 0x22: 150 | returnSignalRGBProtocolVersion(data); 151 | break; 152 | case 0x23: 153 | returnUniqueIdentifier(data); 154 | break; 155 | case 0x24: 156 | sendColors(); 157 | break; 158 | case 0x27: 159 | returnTotalLeds(data); 160 | break; 161 | case 0x28: 162 | returnFirmwareType(data); 163 | break; 164 | } 165 | } 166 | 167 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 168 | { 169 | device.write([0x00, 0x21], 32); 170 | device.pause(30); 171 | commandHandler(); 172 | } 173 | 174 | function returnQMKVersion(data) 175 | { 176 | const QMKVersionByte1 = data[2]; 177 | const QMKVersionByte2 = data[3]; 178 | const QMKVersionByte3 = data[4]; 179 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 180 | device.log("QMK SRGB Plugin Version: "+ Version()); 181 | device.pause(30); 182 | } 183 | 184 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 185 | { 186 | device.write([0x00, 0x22], 32); 187 | device.pause(30); 188 | commandHandler(); 189 | } 190 | 191 | function returnSignalRGBProtocolVersion(data) 192 | { 193 | const ProtocolVersionByte1 = data[2]; 194 | const ProtocolVersionByte2 = data[3]; 195 | const ProtocolVersionByte3 = data[4]; 196 | 197 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 198 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 199 | 200 | 201 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) 202 | { 203 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 204 | } 205 | 206 | device.pause(30); 207 | } 208 | 209 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 210 | { 211 | if(device.write([0x00, 0x23], 32) === -1) 212 | { 213 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 214 | } 215 | 216 | device.pause(30); 217 | commandHandler(); 218 | } 219 | 220 | 221 | function returnUniqueIdentifier(data) 222 | { 223 | const UniqueIdentifierByte1 = data[2]; 224 | const UniqueIdentifierByte2 = data[3]; 225 | const UniqueIdentifierByte3 = data[4]; 226 | 227 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) 228 | { 229 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 230 | } 231 | 232 | device.pause(30); 233 | } 234 | 235 | function requestTotalLeds() //Calculate total number of LEDs 236 | { 237 | device.write([0x00, 0x27], 32); 238 | device.pause(30); 239 | commandHandler(); 240 | } 241 | 242 | function returnTotalLeds(data) 243 | { 244 | LEDCount = data[2]; 245 | device.log("Device Total LED Count: " + LEDCount); 246 | device.pause(30); 247 | } 248 | 249 | function requestFirmwareType() 250 | { 251 | device.write([0x00, 0x28], 32); 252 | device.pause(30); 253 | commandHandler(); 254 | } 255 | 256 | function returnFirmwareType(data) 257 | { 258 | const FirmwareTypeByte = data[2]; 259 | 260 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) 261 | { 262 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 263 | } 264 | 265 | if(FirmwareTypeByte === MainlineQMKFirmware) 266 | { 267 | IsViaKeyboard = false; 268 | device.log("Firmware Type: Mainline"); 269 | } 270 | 271 | if(FirmwareTypeByte === VIAFirmware) 272 | { 273 | IsViaKeyboard = true; 274 | device.log("Firmware Type: VIA"); 275 | } 276 | 277 | device.pause(30); 278 | } 279 | 280 | function effectEnable() //Enable the SignalRGB Effect Mode 281 | { 282 | device.write([0x00, 0x25], 32); 283 | device.pause(30); 284 | } 285 | 286 | function effectDisable() //Revert to Hardware Mode 287 | { 288 | device.write([0x00, 0x26], 32); 289 | device.pause(30); 290 | } 291 | 292 | function createSolidColorArray(color) 293 | { 294 | const rgbdata = new Array(vKeys.length * 3).fill(0); 295 | 296 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 297 | { 298 | const iLedIdx = vKeys[iIdx] * 3; 299 | rgbdata[iLedIdx] = color[0]; 300 | rgbdata[iLedIdx+1] = color[1]; 301 | rgbdata[iLedIdx+2] = color[2]; 302 | } 303 | 304 | return rgbdata; 305 | } 306 | 307 | function grabColors(overrideColor) 308 | { 309 | if(overrideColor) 310 | { 311 | return createSolidColorArray(hexToRgb(overrideColor)); 312 | } 313 | else if (LightingMode === "Forced") 314 | { 315 | return createSolidColorArray(hexToRgb(forcedColor)); 316 | } 317 | 318 | const rgbdata = new Array(vKeys.length * 3).fill(0); 319 | 320 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 321 | { 322 | const iPxX = vKeyPositions[iIdx][0]; 323 | const iPxY = vKeyPositions[iIdx][1]; 324 | let color = device.color(iPxX, iPxY); 325 | 326 | const iLedIdx = vKeys[iIdx] * 3; 327 | rgbdata[iLedIdx] = color[0]; 328 | rgbdata[iLedIdx+1] = color[1]; 329 | rgbdata[iLedIdx+2] = color[2]; 330 | } 331 | 332 | return rgbdata; 333 | } 334 | 335 | function sendColors(overrideColor) 336 | { 337 | const rgbdata = grabColors(overrideColor); 338 | 339 | const LedsPerPacket = 9; 340 | let BytesSent = 0; 341 | let BytesLeft = rgbdata.length; 342 | 343 | while(BytesLeft > 0) 344 | { 345 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 346 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 347 | 348 | BytesLeft -= BytesToSend; 349 | BytesSent += BytesToSend; 350 | } 351 | } 352 | 353 | function StreamLightingData(StartLedIdx, RGBData) 354 | { 355 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 356 | device.write(packet, 33); 357 | } 358 | 359 | function hexToRgb(hex) 360 | { 361 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 362 | const colors = []; 363 | colors[0] = parseInt(result[1], 16); 364 | colors[1] = parseInt(result[2], 16); 365 | colors[2] = parseInt(result[3], 16); 366 | 367 | return colors; 368 | } 369 | 370 | export function Validate(endpoint) 371 | { 372 | return endpoint.interface === 1; 373 | } 374 | 375 | export function ImageUrl() 376 | { 377 | return "https://raw.githubusercontent.com/SRGBmods/QMK-Images/main/images/XBows-KnightPlus-Numpad.png"; 378 | } 379 | -------------------------------------------------------------------------------- /Keychron/Q Series/Plus/Keychron_Q0_Plus_QMK_ANSI_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "Keychron Q0 Plus QMK Keyboard"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x3434; } 4 | export function ProductId() { return 0x0131; } 5 | export function Publisher() { return "WhirlwindFX"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [6, 6]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() 18 | { 19 | return [ 20 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 21 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"000000"}, 22 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 23 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"009bde"}, 24 | ]; 25 | } 26 | 27 | //Plugin Version: Built for Protocol V1.0.6 28 | 29 | const vKeys = 30 | [ 31 | 0, 1, 2, 3, 32 | 4, 5, 6, 7, 8, 33 | 9, 10, 11, 12, 13, 34 | 14, 15, 16, 17, 35 | 18, 19, 20, 21, 22, 36 | 23, 24, 25 37 | ]; 38 | const vKeyNames = 39 | [ 40 | "Circle", "Triangle", "Square", "Cross", 41 | "M1", "NumLock", "Num /", "Num *", "Num -", 42 | "M2", "Num 7", "Num 8", "Num 9", "Num +", 43 | "M3", "Num 4", "Num 5", "Num 6", 44 | "M4", "Num 1", "Num 2", "Num 3", "Num Enter", 45 | "M5", "Num 0", "Num ." 46 | ]; 47 | 48 | const vKeyPositions = 49 | [ 50 | [1, 0], [2, 0], [3, 0], [4, 0], 51 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], 52 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], 53 | [0, 3], [1, 3], [2, 3], [3, 3], 54 | [0, 4], [1, 4], [2, 4], [3, 4], [4, 4], 55 | [0, 5], [1, 5], [3, 5] 56 | ]; 57 | 58 | let LEDCount = 0; 59 | let IsViaKeyboard = false; 60 | const MainlineQMKFirmware = 1; 61 | const VIAFirmware = 2; 62 | const PluginProtocolVersion = "1.0.6"; 63 | 64 | export function LedNames() 65 | { 66 | return vKeyNames; 67 | } 68 | 69 | export function LedPositions() 70 | { 71 | return vKeyPositions; 72 | } 73 | 74 | export function vKeysArrayCount() 75 | { 76 | device.log('vKeys ' + vKeys.length); 77 | device.log('vKeyNames ' + vKeyNames.length); 78 | device.log('vKeyPositions ' + vKeyPositions.length); 79 | } 80 | 81 | export function Initialize() 82 | { 83 | requestFirmwareType(); 84 | requestQMKVersion(); 85 | requestSignalRGBProtocolVersion(); 86 | requestUniqueIdentifier(); 87 | requestTotalLeds(); 88 | effectEnable(); 89 | 90 | } 91 | 92 | export function Render() 93 | { 94 | sendColors(); 95 | } 96 | 97 | export function Shutdown(SystemSuspending) 98 | { 99 | 100 | if(SystemSuspending) 101 | { 102 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 103 | } 104 | else 105 | { 106 | if (shutdownMode === "SignalRGB") 107 | { 108 | sendColors(shutdownColor); 109 | } 110 | else 111 | { 112 | effectDisable(); 113 | } 114 | } 115 | //vKeysArrayCount(); // For debugging array counts 116 | 117 | } 118 | 119 | function commandHandler() 120 | { 121 | const readCounts = []; 122 | 123 | do 124 | { 125 | const returnpacket = device.read([0x00], 32, 10); 126 | processCommands(returnpacket); 127 | 128 | readCounts.push(device.getLastReadSize()); 129 | 130 | // Extra Read to throw away empty packets from Via 131 | // Via always sends a second packet with the same Command Id. 132 | if(IsViaKeyboard) 133 | { 134 | device.read([0x00], 32, 10); 135 | } 136 | } 137 | while(device.getLastReadSize() > 0); 138 | 139 | } 140 | 141 | function processCommands(data) 142 | { 143 | switch(data[1]) 144 | { 145 | case 0x21: 146 | returnQMKVersion(data); 147 | break; 148 | case 0x22: 149 | returnSignalRGBProtocolVersion(data); 150 | break; 151 | case 0x23: 152 | returnUniqueIdentifier(data); 153 | break; 154 | case 0x24: 155 | sendColors(); 156 | break; 157 | case 0x27: 158 | returnTotalLeds(data); 159 | break; 160 | case 0x28: 161 | returnFirmwareType(data); 162 | break; 163 | } 164 | } 165 | 166 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 167 | { 168 | device.write([0x00, 0x21], 32); 169 | device.pause(30); 170 | commandHandler(); 171 | } 172 | 173 | function returnQMKVersion(data) 174 | { 175 | const QMKVersionByte1 = data[2]; 176 | const QMKVersionByte2 = data[3]; 177 | const QMKVersionByte3 = data[4]; 178 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 179 | device.log("QMK SRGB Plugin Version: "+ Version()); 180 | device.pause(30); 181 | } 182 | 183 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 184 | { 185 | device.write([0x00, 0x22], 32); 186 | device.pause(30); 187 | commandHandler(); 188 | } 189 | 190 | function returnSignalRGBProtocolVersion(data) 191 | { 192 | const ProtocolVersionByte1 = data[2]; 193 | const ProtocolVersionByte2 = data[3]; 194 | const ProtocolVersionByte3 = data[4]; 195 | 196 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 197 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 198 | 199 | 200 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) 201 | { 202 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 203 | } 204 | 205 | device.pause(30); 206 | } 207 | 208 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 209 | { 210 | if(device.write([0x00, 0x23], 32) === -1) 211 | { 212 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 213 | } 214 | 215 | device.pause(30); 216 | commandHandler(); 217 | } 218 | 219 | 220 | function returnUniqueIdentifier(data) 221 | { 222 | const UniqueIdentifierByte1 = data[2]; 223 | const UniqueIdentifierByte2 = data[3]; 224 | const UniqueIdentifierByte3 = data[4]; 225 | 226 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) 227 | { 228 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 229 | } 230 | 231 | device.pause(30); 232 | } 233 | 234 | function requestTotalLeds() //Calculate total number of LEDs 235 | { 236 | device.write([0x00, 0x27], 32); 237 | device.pause(30); 238 | commandHandler(); 239 | } 240 | 241 | function returnTotalLeds(data) 242 | { 243 | LEDCount = data[2]; 244 | device.log("Device Total LED Count: " + LEDCount); 245 | device.pause(30); 246 | } 247 | 248 | function requestFirmwareType() 249 | { 250 | device.write([0x00, 0x28], 32); 251 | device.pause(30); 252 | commandHandler(); 253 | } 254 | 255 | function returnFirmwareType(data) 256 | { 257 | const FirmwareTypeByte = data[2]; 258 | 259 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) 260 | { 261 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 262 | } 263 | 264 | if(FirmwareTypeByte === MainlineQMKFirmware) 265 | { 266 | IsViaKeyboard = false; 267 | device.log("Firmware Type: Mainline"); 268 | } 269 | 270 | if(FirmwareTypeByte === VIAFirmware) 271 | { 272 | IsViaKeyboard = true; 273 | device.log("Firmware Type: VIA"); 274 | } 275 | 276 | device.pause(30); 277 | } 278 | 279 | function effectEnable() //Enable the SignalRGB Effect Mode 280 | { 281 | device.write([0x00, 0x25], 32); 282 | device.pause(30); 283 | } 284 | 285 | function effectDisable() //Revert to Hardware Mode 286 | { 287 | device.write([0x00, 0x26], 32); 288 | device.pause(30); 289 | } 290 | 291 | function createSolidColorArray(color) 292 | { 293 | const rgbdata = new Array(vKeys.length * 3).fill(0); 294 | 295 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 296 | { 297 | const iLedIdx = vKeys[iIdx] * 3; 298 | rgbdata[iLedIdx] = color[0]; 299 | rgbdata[iLedIdx+1] = color[1]; 300 | rgbdata[iLedIdx+2] = color[2]; 301 | } 302 | 303 | return rgbdata; 304 | } 305 | 306 | function grabColors(overrideColor) 307 | { 308 | if(overrideColor) 309 | { 310 | return createSolidColorArray(hexToRgb(overrideColor)); 311 | } 312 | else if (LightingMode === "Forced") 313 | { 314 | return createSolidColorArray(hexToRgb(forcedColor)); 315 | } 316 | 317 | const rgbdata = new Array(vKeys.length * 3).fill(0); 318 | 319 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 320 | { 321 | const iPxX = vKeyPositions[iIdx][0]; 322 | const iPxY = vKeyPositions[iIdx][1]; 323 | let color = device.color(iPxX, iPxY); 324 | 325 | const iLedIdx = vKeys[iIdx] * 3; 326 | rgbdata[iLedIdx] = color[0]; 327 | rgbdata[iLedIdx+1] = color[1]; 328 | rgbdata[iLedIdx+2] = color[2]; 329 | } 330 | 331 | return rgbdata; 332 | } 333 | 334 | function sendColors(overrideColor) 335 | { 336 | const rgbdata = grabColors(overrideColor); 337 | 338 | const LedsPerPacket = 9; 339 | let BytesSent = 0; 340 | let BytesLeft = rgbdata.length; 341 | 342 | while(BytesLeft > 0) 343 | { 344 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 345 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 346 | 347 | BytesLeft -= BytesToSend; 348 | BytesSent += BytesToSend; 349 | } 350 | } 351 | 352 | function StreamLightingData(StartLedIdx, RGBData) 353 | { 354 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 355 | device.write(packet, 33); 356 | } 357 | 358 | function hexToRgb(hex) 359 | { 360 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 361 | const colors = []; 362 | colors[0] = parseInt(result[1], 16); 363 | colors[1] = parseInt(result[2], 16); 364 | colors[2] = parseInt(result[3], 16); 365 | 366 | return colors; 367 | } 368 | 369 | export function Validate(endpoint) 370 | { 371 | return endpoint.interface === 1; 372 | } 373 | 374 | export function Image() 375 | { 376 | return ""; 377 | } -------------------------------------------------------------------------------- /Ergodox_EZ/Ergodox_EZ_Glow_QMK.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "Ergodox EZ Glow"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x3297; } 4 | export function ProductId() { return 0x4976; } 5 | export function Publisher() { return "WhirlwindFX"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [14, 5]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() 18 | { 19 | return [ 20 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 21 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"000000"}, 22 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 23 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"009bde"}, 24 | ]; 25 | } 26 | 27 | //Plugin Version: Built for Protocol V1.0.6 28 | 29 | const vKeys = [ 30 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 31 | 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 32 | 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 33 | 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 34 | 40, 41, 42, 43, 44, 45, 46, 47 35 | ]; 36 | 37 | const vKeyNames = [ 38 | "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", 39 | "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", 40 | "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", 41 | "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", 42 | "\"", "", "Lf", "Rt", "Up", "Dn", "]", "[" 43 | ]; 44 | 45 | const vKeyPositions = [ 46 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], 47 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], 48 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [8, 2], [9, 2], [10, 2], [11, 2], [12, 2], 49 | [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [8, 3], [9, 3], [10, 3], [11, 3], [12, 3], 50 | [0, 4], [1, 4], [2, 4], [3, 4], [9, 4], [10, 4], [11, 4], [12, 4] 51 | ]; 52 | 53 | let LEDCount = 0; 54 | let IsViaKeyboard = false; 55 | const MainlineQMKFirmware = 1; 56 | const VIAFirmware = 2; 57 | const PluginProtocolVersion = "1.0.6"; 58 | 59 | export function LedNames() 60 | { 61 | return vKeyNames; 62 | } 63 | 64 | export function LedPositions() 65 | { 66 | return vKeyPositions; 67 | } 68 | 69 | export function vKeysArrayCount() 70 | { 71 | device.log('vKeys ' + vKeys.length); 72 | device.log('vKeyNames ' + vKeyNames.length); 73 | device.log('vKeyPositions ' + vKeyPositions.length); 74 | } 75 | 76 | export function Initialize() 77 | { 78 | requestFirmwareType(); 79 | requestQMKVersion(); 80 | requestSignalRGBProtocolVersion(); 81 | requestUniqueIdentifier(); 82 | requestTotalLeds(); 83 | effectEnable(); 84 | 85 | } 86 | 87 | export function Render() 88 | { 89 | sendColors(); 90 | } 91 | 92 | export function Shutdown(SystemSuspending) 93 | { 94 | 95 | if(SystemSuspending) 96 | { 97 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 98 | } 99 | else 100 | { 101 | if (shutdownMode === "SignalRGB") 102 | { 103 | sendColors(shutdownColor); 104 | } 105 | else 106 | { 107 | effectDisable(); 108 | } 109 | } 110 | //vKeysArrayCount(); // For debugging array counts 111 | 112 | } 113 | 114 | function commandHandler() 115 | { 116 | const readCounts = []; 117 | 118 | do 119 | { 120 | const returnpacket = device.read([0x00], 32, 10); 121 | processCommands(returnpacket); 122 | 123 | readCounts.push(device.getLastReadSize()); 124 | 125 | // Extra Read to throw away empty packets from Via 126 | // Via always sends a second packet with the same Command Id. 127 | if(IsViaKeyboard) 128 | { 129 | device.read([0x00], 32, 10); 130 | } 131 | } 132 | while(device.getLastReadSize() > 0); 133 | 134 | } 135 | 136 | function processCommands(data) 137 | { 138 | switch(data[1]) 139 | { 140 | case 0x21: 141 | returnQMKVersion(data); 142 | break; 143 | case 0x22: 144 | returnSignalRGBProtocolVersion(data); 145 | break; 146 | case 0x23: 147 | returnUniqueIdentifier(data); 148 | break; 149 | case 0x24: 150 | sendColors(); 151 | break; 152 | case 0x27: 153 | returnTotalLeds(data); 154 | break; 155 | case 0x28: 156 | returnFirmwareType(data); 157 | break; 158 | } 159 | } 160 | 161 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 162 | { 163 | device.write([0x00, 0x21], 32); 164 | device.pause(30); 165 | commandHandler(); 166 | } 167 | 168 | function returnQMKVersion(data) 169 | { 170 | const QMKVersionByte1 = data[2]; 171 | const QMKVersionByte2 = data[3]; 172 | const QMKVersionByte3 = data[4]; 173 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 174 | device.log("QMK SRGB Plugin Version: "+ Version()); 175 | device.pause(30); 176 | } 177 | 178 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 179 | { 180 | device.write([0x00, 0x22], 32); 181 | device.pause(30); 182 | commandHandler(); 183 | } 184 | 185 | function returnSignalRGBProtocolVersion(data) 186 | { 187 | const ProtocolVersionByte1 = data[2]; 188 | const ProtocolVersionByte2 = data[3]; 189 | const ProtocolVersionByte3 = data[4]; 190 | 191 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 192 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 193 | 194 | 195 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) 196 | { 197 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 198 | } 199 | 200 | device.pause(30); 201 | } 202 | 203 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 204 | { 205 | if(device.write([0x00, 0x23], 32) === -1) 206 | { 207 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 208 | } 209 | 210 | device.pause(30); 211 | commandHandler(); 212 | } 213 | 214 | 215 | function returnUniqueIdentifier(data) 216 | { 217 | const UniqueIdentifierByte1 = data[2]; 218 | const UniqueIdentifierByte2 = data[3]; 219 | const UniqueIdentifierByte3 = data[4]; 220 | 221 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) 222 | { 223 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 224 | } 225 | 226 | device.pause(30); 227 | } 228 | 229 | function requestTotalLeds() //Calculate total number of LEDs 230 | { 231 | device.write([0x00, 0x27], 32); 232 | device.pause(30); 233 | commandHandler(); 234 | } 235 | 236 | function returnTotalLeds(data) 237 | { 238 | LEDCount = data[2]; 239 | device.log("Device Total LED Count: " + LEDCount); 240 | device.pause(30); 241 | } 242 | 243 | function requestFirmwareType() 244 | { 245 | device.write([0x00, 0x28], 32); 246 | device.pause(30); 247 | commandHandler(); 248 | } 249 | 250 | function returnFirmwareType(data) 251 | { 252 | const FirmwareTypeByte = data[2]; 253 | 254 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) 255 | { 256 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 257 | } 258 | 259 | if(FirmwareTypeByte === MainlineQMKFirmware) 260 | { 261 | IsViaKeyboard = false; 262 | device.log("Firmware Type: Mainline"); 263 | } 264 | 265 | if(FirmwareTypeByte === VIAFirmware) 266 | { 267 | IsViaKeyboard = true; 268 | device.log("Firmware Type: VIA"); 269 | } 270 | 271 | device.pause(30); 272 | } 273 | 274 | function effectEnable() //Enable the SignalRGB Effect Mode 275 | { 276 | device.write([0x00, 0x25], 32); 277 | device.pause(30); 278 | } 279 | 280 | function effectDisable() //Revert to Hardware Mode 281 | { 282 | device.write([0x00, 0x26], 32); 283 | device.pause(30); 284 | } 285 | 286 | function createSolidColorArray(color) 287 | { 288 | const rgbdata = new Array(vKeys.length * 3).fill(0); 289 | 290 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 291 | { 292 | const iLedIdx = vKeys[iIdx] * 3; 293 | rgbdata[iLedIdx] = color[0]; 294 | rgbdata[iLedIdx+1] = color[1]; 295 | rgbdata[iLedIdx+2] = color[2]; 296 | } 297 | 298 | return rgbdata; 299 | } 300 | 301 | function grabColors(overrideColor) 302 | { 303 | if(overrideColor) 304 | { 305 | return createSolidColorArray(hexToRgb(overrideColor)); 306 | } 307 | else if (LightingMode === "Forced") 308 | { 309 | return createSolidColorArray(hexToRgb(forcedColor)); 310 | } 311 | 312 | const rgbdata = new Array(vKeys.length * 3).fill(0); 313 | 314 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 315 | { 316 | const iPxX = vKeyPositions[iIdx][0]; 317 | const iPxY = vKeyPositions[iIdx][1]; 318 | let color = device.color(iPxX, iPxY); 319 | 320 | const iLedIdx = vKeys[iIdx] * 3; 321 | rgbdata[iLedIdx] = color[0]; 322 | rgbdata[iLedIdx+1] = color[1]; 323 | rgbdata[iLedIdx+2] = color[2]; 324 | } 325 | 326 | return rgbdata; 327 | } 328 | 329 | function sendColors(overrideColor) 330 | { 331 | const rgbdata = grabColors(overrideColor); 332 | 333 | const LedsPerPacket = 9; 334 | let BytesSent = 0; 335 | let BytesLeft = rgbdata.length; 336 | 337 | while(BytesLeft > 0) 338 | { 339 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 340 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 341 | 342 | BytesLeft -= BytesToSend; 343 | BytesSent += BytesToSend; 344 | } 345 | } 346 | 347 | function StreamLightingData(StartLedIdx, RGBData) 348 | { 349 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 350 | device.write(packet, 33); 351 | } 352 | 353 | function hexToRgb(hex) 354 | { 355 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 356 | const colors = []; 357 | colors[0] = parseInt(result[1], 16); 358 | colors[1] = parseInt(result[2], 16); 359 | colors[2] = parseInt(result[3], 16); 360 | 361 | return colors; 362 | } 363 | 364 | export function Validate(endpoint) 365 | { 366 | return endpoint.interface === 1; 367 | } -------------------------------------------------------------------------------- /GMMK/GMMK_Numpad_QMK.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "GMMK Numpad"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x320F; } 4 | export function ProductId() { return 0x5088; } 5 | export function Publisher() { return "WhirlwindFX"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard";} 8 | export function Size() { return [6, 7]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() 18 | { 19 | return [ 20 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 21 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"000000"}, 22 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 23 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"009bde"}, 24 | ]; 25 | } 26 | 27 | //Plugin Version: Built for Protocol V1.0.6 28 | 29 | const vKeys = [ 30 | 17, 0, 1, 2, 3, 24, 31 | 18, 4, 5, 6, 7, 25, 32 | 19, 8, 9, 10, 26, 33 | 20, 11, 12, 13, 14, 27, 34 | 21, 15, 16, 28, 35 | 22, 29, 36 | 23, 30, 37 | 38 | ]; 39 | 40 | const vKeyNames = [ 41 | "Sidestrip 1", "NumLock", "Num /", "Num *", "Num -", "Sidestrip 8", 42 | "Sidestrip 2", "Num 7", "Num 8", "Num 9", "Num +", "Sidestrip 9", 43 | "Sidestrip 3", "Num 4", "Num 5", "Num 6", "Sidestrip 10", 44 | "Sidestrip 4", "Num 1", "Num 2", "Num 3", "Num Enter", "Sidestrip 11", 45 | "Sidestrip 5", "Num 0", "Num .", "Sidestrip 12", 46 | "Sidestrip 6", "Sidestrip 13", 47 | "Sidestrip 7", "Sidestrip 14", 48 | 49 | ]; 50 | 51 | const vKeyPositions = [ 52 | [4, 0], [0, 0], [1, 0], [2, 0], [3, 0], [5, 0], 53 | [4, 1], [0, 1], [1, 1], [2, 1], [3, 1], [5, 1], 54 | [4, 2], [0, 2], [1, 2], [2, 2], [5, 2], 55 | [4, 3], [0, 3], [1, 3], [2, 3], [3, 3], [5, 3], 56 | [4, 4], [0, 4], [1, 4], [5, 4], 57 | [4, 5], [5, 5], 58 | [4, 6], [5, 6] 59 | 60 | ]; 61 | 62 | let LEDCount = 0; 63 | let IsViaKeyboard = false; 64 | const MainlineQMKFirmware = 1; 65 | const VIAFirmware = 2; 66 | const PluginProtocolVersion = "1.0.6"; 67 | 68 | export function LedNames() 69 | { 70 | return vKeyNames; 71 | } 72 | 73 | export function LedPositions() 74 | { 75 | return vKeyPositions; 76 | } 77 | 78 | export function vKeysArrayCount() 79 | { 80 | device.log('vKeys ' + vKeys.length); 81 | device.log('vKeyNames ' + vKeyNames.length); 82 | device.log('vKeyPositions ' + vKeyPositions.length); 83 | } 84 | 85 | export function Initialize() 86 | { 87 | requestFirmwareType(); 88 | requestQMKVersion(); 89 | requestSignalRGBProtocolVersion(); 90 | requestUniqueIdentifier(); 91 | requestTotalLeds(); 92 | effectEnable(); 93 | 94 | } 95 | 96 | export function Render() 97 | { 98 | sendColors(); 99 | } 100 | 101 | export function Shutdown(SystemSuspending) 102 | { 103 | 104 | if(SystemSuspending) 105 | { 106 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 107 | } 108 | else 109 | { 110 | if (shutdownMode === "SignalRGB") 111 | { 112 | sendColors(shutdownColor); 113 | } 114 | else 115 | { 116 | effectDisable(); 117 | } 118 | } 119 | //vKeysArrayCount(); // For debugging array counts 120 | 121 | } 122 | 123 | function commandHandler() 124 | { 125 | const readCounts = []; 126 | 127 | do 128 | { 129 | const returnpacket = device.read([0x00], 32, 10); 130 | processCommands(returnpacket); 131 | 132 | readCounts.push(device.getLastReadSize()); 133 | 134 | // Extra Read to throw away empty packets from Via 135 | // Via always sends a second packet with the same Command Id. 136 | if(IsViaKeyboard) 137 | { 138 | device.read([0x00], 32, 10); 139 | } 140 | } 141 | while(device.getLastReadSize() > 0); 142 | 143 | } 144 | 145 | function processCommands(data) 146 | { 147 | switch(data[1]) 148 | { 149 | case 0x21: 150 | returnQMKVersion(data); 151 | break; 152 | case 0x22: 153 | returnSignalRGBProtocolVersion(data); 154 | break; 155 | case 0x23: 156 | returnUniqueIdentifier(data); 157 | break; 158 | case 0x24: 159 | sendColors(); 160 | break; 161 | case 0x27: 162 | returnTotalLeds(data); 163 | break; 164 | case 0x28: 165 | returnFirmwareType(data); 166 | break; 167 | } 168 | } 169 | 170 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 171 | { 172 | device.write([0x00, 0x21], 32); 173 | device.pause(30); 174 | commandHandler(); 175 | } 176 | 177 | function returnQMKVersion(data) 178 | { 179 | const QMKVersionByte1 = data[2]; 180 | const QMKVersionByte2 = data[3]; 181 | const QMKVersionByte3 = data[4]; 182 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 183 | device.log("QMK SRGB Plugin Version: "+ Version()); 184 | device.pause(30); 185 | } 186 | 187 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 188 | { 189 | device.write([0x00, 0x22], 32); 190 | device.pause(30); 191 | commandHandler(); 192 | } 193 | 194 | function returnSignalRGBProtocolVersion(data) 195 | { 196 | const ProtocolVersionByte1 = data[2]; 197 | const ProtocolVersionByte2 = data[3]; 198 | const ProtocolVersionByte3 = data[4]; 199 | 200 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 201 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 202 | 203 | 204 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) 205 | { 206 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 207 | } 208 | 209 | device.pause(30); 210 | } 211 | 212 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 213 | { 214 | if(device.write([0x00, 0x23], 32) === -1) 215 | { 216 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 217 | } 218 | 219 | device.pause(30); 220 | commandHandler(); 221 | } 222 | 223 | 224 | function returnUniqueIdentifier(data) 225 | { 226 | const UniqueIdentifierByte1 = data[2]; 227 | const UniqueIdentifierByte2 = data[3]; 228 | const UniqueIdentifierByte3 = data[4]; 229 | 230 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) 231 | { 232 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 233 | } 234 | 235 | device.pause(30); 236 | } 237 | 238 | function requestTotalLeds() //Calculate total number of LEDs 239 | { 240 | device.write([0x00, 0x27], 32); 241 | device.pause(30); 242 | commandHandler(); 243 | } 244 | 245 | function returnTotalLeds(data) 246 | { 247 | LEDCount = data[2]; 248 | device.log("Device Total LED Count: " + LEDCount); 249 | device.pause(30); 250 | } 251 | 252 | function requestFirmwareType() 253 | { 254 | device.write([0x00, 0x28], 32); 255 | device.pause(30); 256 | commandHandler(); 257 | } 258 | 259 | function returnFirmwareType(data) 260 | { 261 | const FirmwareTypeByte = data[2]; 262 | 263 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) 264 | { 265 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 266 | } 267 | 268 | if(FirmwareTypeByte === MainlineQMKFirmware) 269 | { 270 | IsViaKeyboard = false; 271 | device.log("Firmware Type: Mainline"); 272 | } 273 | 274 | if(FirmwareTypeByte === VIAFirmware) 275 | { 276 | IsViaKeyboard = true; 277 | device.log("Firmware Type: VIA"); 278 | } 279 | 280 | device.pause(30); 281 | } 282 | 283 | function effectEnable() //Enable the SignalRGB Effect Mode 284 | { 285 | device.write([0x00, 0x25], 32); 286 | device.pause(30); 287 | } 288 | 289 | function effectDisable() //Revert to Hardware Mode 290 | { 291 | device.write([0x00, 0x26], 32); 292 | device.pause(30); 293 | } 294 | 295 | function createSolidColorArray(color) 296 | { 297 | const rgbdata = new Array(vKeys.length * 3).fill(0); 298 | 299 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 300 | { 301 | const iLedIdx = vKeys[iIdx] * 3; 302 | rgbdata[iLedIdx] = color[0]; 303 | rgbdata[iLedIdx+1] = color[1]; 304 | rgbdata[iLedIdx+2] = color[2]; 305 | } 306 | 307 | return rgbdata; 308 | } 309 | 310 | function grabColors(overrideColor) 311 | { 312 | if(overrideColor) 313 | { 314 | return createSolidColorArray(hexToRgb(overrideColor)); 315 | } 316 | else if (LightingMode === "Forced") 317 | { 318 | return createSolidColorArray(hexToRgb(forcedColor)); 319 | } 320 | 321 | const rgbdata = new Array(vKeys.length * 3).fill(0); 322 | 323 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 324 | { 325 | const iPxX = vKeyPositions[iIdx][0]; 326 | const iPxY = vKeyPositions[iIdx][1]; 327 | let color = device.color(iPxX, iPxY); 328 | 329 | const iLedIdx = vKeys[iIdx] * 3; 330 | rgbdata[iLedIdx] = color[0]; 331 | rgbdata[iLedIdx+1] = color[1]; 332 | rgbdata[iLedIdx+2] = color[2]; 333 | } 334 | 335 | return rgbdata; 336 | } 337 | 338 | function sendColors(overrideColor) 339 | { 340 | const rgbdata = grabColors(overrideColor); 341 | 342 | const LedsPerPacket = 9; 343 | let BytesSent = 0; 344 | let BytesLeft = rgbdata.length; 345 | 346 | while(BytesLeft > 0) 347 | { 348 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 349 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 350 | 351 | BytesLeft -= BytesToSend; 352 | BytesSent += BytesToSend; 353 | } 354 | } 355 | 356 | function StreamLightingData(StartLedIdx, RGBData) 357 | { 358 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 359 | device.write(packet, 33); 360 | } 361 | 362 | function hexToRgb(hex) 363 | { 364 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 365 | const colors = []; 366 | colors[0] = parseInt(result[1], 16); 367 | colors[1] = parseInt(result[2], 16); 368 | colors[2] = parseInt(result[3], 16); 369 | 370 | return colors; 371 | } 372 | 373 | export function Validate(endpoint) 374 | { 375 | return endpoint.interface === 1; 376 | } -------------------------------------------------------------------------------- /Keychron/K Series/Pro/Keychron_K12_Pro_QMK_ANSI_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "Keychron K12 QMK Keyboard"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x3434; } 4 | export function ProductId() { return 0x02C0; } 5 | export function Publisher() { return "WhirlwindFX"; } 6 | export function Documentation(){ return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [14, 5]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() { 18 | return [ 19 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 20 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#000000"}, 21 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 22 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 23 | ]; 24 | } 25 | 26 | //Plugin Version: Built for Protocol V1.0.6 27 | 28 | const vKeys = [ 29 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, //14 30 | 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, //14 31 | 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, //13 32 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, //12 33 | 53, 54, 55, 56, 57, 58, 59, 60, //8 34 | ]; 35 | 36 | const vKeyNames = [ 37 | "Esc", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", //14 38 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", //14 39 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter", //13 40 | "Left Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Right Shift", //12 41 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Alt", "Menu", "Fn", "Ctrl", //8 42 | ]; 43 | 44 | const vKeyPositions = [ 45 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], //14 46 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], //14 47 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [13, 2], //13 48 | [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [13, 3], //12 49 | [0, 4], [1, 4], [2, 4], [6, 4], [10, 4], [11, 4], [12, 4], [13, 4], //8 50 | ]; 51 | 52 | let LEDCount = 0; 53 | let IsViaKeyboard = false; 54 | const MainlineQMKFirmware = 1; 55 | const VIAFirmware = 2; 56 | const PluginProtocolVersion = "1.0.6"; 57 | 58 | export function LedNames() { 59 | return vKeyNames; 60 | } 61 | 62 | export function LedPositions() { 63 | return vKeyPositions; 64 | } 65 | 66 | export function vKeysArrayCount() { 67 | device.log('vKeys ' + vKeys.length); 68 | device.log('vKeyNames ' + vKeyNames.length); 69 | device.log('vKeyPositions ' + vKeyPositions.length); 70 | } 71 | 72 | export function Initialize() { 73 | requestFirmwareType(); 74 | requestQMKVersion(); 75 | requestSignalRGBProtocolVersion(); 76 | requestUniqueIdentifier(); 77 | requestTotalLeds(); 78 | effectEnable(); 79 | 80 | } 81 | 82 | export function Render() { 83 | sendColors(); 84 | } 85 | 86 | export function Shutdown(SystemSuspending) { 87 | 88 | if(SystemSuspending) { 89 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 90 | } else { 91 | if (shutdownMode === "SignalRGB") { 92 | sendColors(shutdownColor); 93 | } else { 94 | effectDisable(); 95 | } 96 | } 97 | 98 | vKeysArrayCount(); // For debugging array counts 99 | 100 | } 101 | 102 | function commandHandler() { 103 | const readCounts = []; 104 | 105 | do { 106 | const returnpacket = device.read([0x00], 32, 10); 107 | processCommands(returnpacket); 108 | 109 | readCounts.push(device.getLastReadSize()); 110 | 111 | // Extra Read to throw away empty packets from Via 112 | // Via always sends a second packet with the same Command Id. 113 | if(IsViaKeyboard) { 114 | device.read([0x00], 32, 10); 115 | } 116 | } 117 | while(device.getLastReadSize() > 0); 118 | 119 | } 120 | 121 | function processCommands(data) { 122 | switch(data[1]) { 123 | case 0x21: 124 | returnQMKVersion(data); 125 | break; 126 | case 0x22: 127 | returnSignalRGBProtocolVersion(data); 128 | break; 129 | case 0x23: 130 | returnUniqueIdentifier(data); 131 | break; 132 | case 0x24: 133 | sendColors(); 134 | break; 135 | case 0x27: 136 | returnTotalLeds(data); 137 | break; 138 | case 0x28: 139 | returnFirmwareType(data); 140 | break; 141 | } 142 | } 143 | 144 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 145 | { 146 | device.write([0x00, 0x21], 32); 147 | device.pause(30); 148 | commandHandler(); 149 | } 150 | 151 | function returnQMKVersion(data) { 152 | const QMKVersionByte1 = data[2]; 153 | const QMKVersionByte2 = data[3]; 154 | const QMKVersionByte3 = data[4]; 155 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 156 | device.log("QMK SRGB Plugin Version: "+ Version()); 157 | device.pause(30); 158 | } 159 | 160 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 161 | { 162 | device.write([0x00, 0x22], 32); 163 | device.pause(30); 164 | commandHandler(); 165 | } 166 | 167 | function returnSignalRGBProtocolVersion(data) { 168 | const ProtocolVersionByte1 = data[2]; 169 | const ProtocolVersionByte2 = data[3]; 170 | const ProtocolVersionByte3 = data[4]; 171 | 172 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 173 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 174 | 175 | 176 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) { 177 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 178 | } 179 | 180 | device.pause(30); 181 | } 182 | 183 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 184 | { 185 | if(device.write([0x00, 0x23], 32) === -1) { 186 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 187 | } 188 | 189 | device.pause(30); 190 | commandHandler(); 191 | } 192 | 193 | 194 | function returnUniqueIdentifier(data) { 195 | const UniqueIdentifierByte1 = data[2]; 196 | const UniqueIdentifierByte2 = data[3]; 197 | const UniqueIdentifierByte3 = data[4]; 198 | 199 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) { 200 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 201 | } 202 | 203 | device.pause(30); 204 | } 205 | 206 | function requestTotalLeds() //Calculate total number of LEDs 207 | { 208 | device.write([0x00, 0x27], 32); 209 | device.pause(30); 210 | commandHandler(); 211 | } 212 | 213 | function returnTotalLeds(data) { 214 | LEDCount = data[2]; 215 | device.log("Device Total LED Count: " + LEDCount); 216 | device.pause(30); 217 | } 218 | 219 | function requestFirmwareType() { 220 | device.write([0x00, 0x28], 32); 221 | device.pause(30); 222 | commandHandler(); 223 | } 224 | 225 | function returnFirmwareType(data) { 226 | const FirmwareTypeByte = data[2]; 227 | 228 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) { 229 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 230 | } 231 | 232 | if(FirmwareTypeByte === MainlineQMKFirmware) { 233 | IsViaKeyboard = false; 234 | device.log("Firmware Type: Mainline"); 235 | } 236 | 237 | if(FirmwareTypeByte === VIAFirmware) { 238 | IsViaKeyboard = true; 239 | device.log("Firmware Type: VIA"); 240 | } 241 | 242 | device.pause(30); 243 | } 244 | 245 | function effectEnable() //Enable the SignalRGB Effect Mode 246 | { 247 | device.write([0x00, 0x25], 32); 248 | device.pause(30); 249 | } 250 | 251 | function effectDisable() //Revert to Hardware Mode 252 | { 253 | device.write([0x00, 0x26], 32); 254 | device.pause(30); 255 | } 256 | 257 | function createSolidColorArray(color) { 258 | const rgbdata = new Array(vKeys.length * 3).fill(0); 259 | 260 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 261 | const iLedIdx = vKeys[iIdx] * 3; 262 | rgbdata[iLedIdx] = color[0]; 263 | rgbdata[iLedIdx+1] = color[1]; 264 | rgbdata[iLedIdx+2] = color[2]; 265 | } 266 | 267 | return rgbdata; 268 | } 269 | 270 | function grabColors(overrideColor) { 271 | if(overrideColor) { 272 | return createSolidColorArray(hexToRgb(overrideColor)); 273 | } else if (LightingMode === "Forced") { 274 | return createSolidColorArray(hexToRgb(forcedColor)); 275 | } 276 | 277 | const rgbdata = new Array(vKeys.length * 3).fill(0); 278 | 279 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 280 | const iPxX = vKeyPositions[iIdx][0]; 281 | const iPxY = vKeyPositions[iIdx][1]; 282 | const color = device.color(iPxX, iPxY); 283 | 284 | const iLedIdx = vKeys[iIdx] * 3; 285 | rgbdata[iLedIdx] = color[0]; 286 | rgbdata[iLedIdx+1] = color[1]; 287 | rgbdata[iLedIdx+2] = color[2]; 288 | } 289 | 290 | return rgbdata; 291 | } 292 | 293 | function sendColors(overrideColor) { 294 | const rgbdata = grabColors(overrideColor); 295 | 296 | const LedsPerPacket = 9; 297 | let BytesSent = 0; 298 | let BytesLeft = rgbdata.length; 299 | 300 | while(BytesLeft > 0) { 301 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 302 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 303 | 304 | BytesLeft -= BytesToSend; 305 | BytesSent += BytesToSend; 306 | } 307 | } 308 | 309 | function StreamLightingData(StartLedIdx, RGBData) { 310 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 311 | device.write(packet, 33); 312 | } 313 | 314 | function hexToRgb(hex) { 315 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 316 | const colors = []; 317 | colors[0] = parseInt(result[1], 16); 318 | colors[1] = parseInt(result[2], 16); 319 | colors[2] = parseInt(result[3], 16); 320 | 321 | return colors; 322 | } 323 | 324 | export function Validate(endpoint) { 325 | return endpoint.interface === 1; 326 | } 327 | 328 | export function Image() { 329 | return ""; 330 | } -------------------------------------------------------------------------------- /Keychron/V Series/Standard/Keychron_V4_QMK_ANSI_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "Keychron V4 QMK ANSI Keyboard"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x3434; } 4 | export function ProductId() { return 0x0340; } 5 | export function Publisher() { return "WhirlwindFX"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [14, 5]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() { 18 | return [ 19 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 20 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#000000"}, 21 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 22 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 23 | ]; 24 | } 25 | 26 | //Plugin Version: Built for Protocol V1.0.6 27 | 28 | const vKeys = [ 29 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, //14 30 | 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, //14 31 | 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, //13 32 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, //12 33 | 53, 54, 55, 56, 57, 58, 59, 60 //8 34 | ]; 35 | 36 | const vKeyNames = [ 37 | "Esc", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", //14 38 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", //14 39 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter", //13 40 | "Left Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Right Shift", //12 41 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Alt", "Menu", "Fn", "Ctrl", //8 42 | ]; 43 | 44 | const vKeyPositions = [ 45 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], //14 46 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], //14 47 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [13, 2], //13 48 | [0, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [11, 3], [13, 3], //13 49 | [0, 4], [1, 4], [2, 4], [6, 4], [10, 4], [11, 4], [12, 4], [13, 4], //8 50 | ]; 51 | 52 | let LEDCount = 0; 53 | let IsViaKeyboard = false; 54 | const MainlineQMKFirmware = 1; 55 | const VIAFirmware = 2; 56 | const PluginProtocolVersion = "1.0.6"; 57 | 58 | export function LedNames() { 59 | return vKeyNames; 60 | } 61 | 62 | export function LedPositions() { 63 | return vKeyPositions; 64 | } 65 | 66 | export function vKeysArrayCount() { 67 | device.log('vKeys ' + vKeys.length); 68 | device.log('vKeyNames ' + vKeyNames.length); 69 | device.log('vKeyPositions ' + vKeyPositions.length); 70 | } 71 | 72 | export function Initialize() { 73 | requestFirmwareType(); 74 | requestQMKVersion(); 75 | requestSignalRGBProtocolVersion(); 76 | requestUniqueIdentifier(); 77 | requestTotalLeds(); 78 | effectEnable(); 79 | 80 | } 81 | 82 | export function Render() { 83 | sendColors(); 84 | } 85 | 86 | export function Shutdown(SystemSuspending) { 87 | 88 | if(SystemSuspending) { 89 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 90 | } else { 91 | if (shutdownMode === "SignalRGB") { 92 | sendColors(shutdownColor); 93 | } else { 94 | effectDisable(); 95 | } 96 | } 97 | 98 | vKeysArrayCount(); // For debugging array counts 99 | 100 | } 101 | 102 | function commandHandler() { 103 | const readCounts = []; 104 | 105 | do { 106 | const returnpacket = device.read([0x00], 32, 10); 107 | processCommands(returnpacket); 108 | 109 | readCounts.push(device.getLastReadSize()); 110 | 111 | // Extra Read to throw away empty packets from Via 112 | // Via always sends a second packet with the same Command Id. 113 | if(IsViaKeyboard) { 114 | device.read([0x00], 32, 10); 115 | } 116 | } 117 | while(device.getLastReadSize() > 0); 118 | 119 | } 120 | 121 | function processCommands(data) { 122 | switch(data[1]) { 123 | case 0x21: 124 | returnQMKVersion(data); 125 | break; 126 | case 0x22: 127 | returnSignalRGBProtocolVersion(data); 128 | break; 129 | case 0x23: 130 | returnUniqueIdentifier(data); 131 | break; 132 | case 0x24: 133 | sendColors(); 134 | break; 135 | case 0x27: 136 | returnTotalLeds(data); 137 | break; 138 | case 0x28: 139 | returnFirmwareType(data); 140 | break; 141 | } 142 | } 143 | 144 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 145 | { 146 | device.write([0x00, 0x21], 32); 147 | device.pause(30); 148 | commandHandler(); 149 | } 150 | 151 | function returnQMKVersion(data) { 152 | const QMKVersionByte1 = data[2]; 153 | const QMKVersionByte2 = data[3]; 154 | const QMKVersionByte3 = data[4]; 155 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 156 | device.log("QMK SRGB Plugin Version: "+ Version()); 157 | device.pause(30); 158 | } 159 | 160 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 161 | { 162 | device.write([0x00, 0x22], 32); 163 | device.pause(30); 164 | commandHandler(); 165 | } 166 | 167 | function returnSignalRGBProtocolVersion(data) { 168 | const ProtocolVersionByte1 = data[2]; 169 | const ProtocolVersionByte2 = data[3]; 170 | const ProtocolVersionByte3 = data[4]; 171 | 172 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 173 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 174 | 175 | 176 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) { 177 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 178 | } 179 | 180 | device.pause(30); 181 | } 182 | 183 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 184 | { 185 | if(device.write([0x00, 0x23], 32) === -1) { 186 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 187 | } 188 | 189 | device.pause(30); 190 | commandHandler(); 191 | } 192 | 193 | 194 | function returnUniqueIdentifier(data) { 195 | const UniqueIdentifierByte1 = data[2]; 196 | const UniqueIdentifierByte2 = data[3]; 197 | const UniqueIdentifierByte3 = data[4]; 198 | 199 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) { 200 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 201 | } 202 | 203 | device.pause(30); 204 | } 205 | 206 | function requestTotalLeds() //Calculate total number of LEDs 207 | { 208 | device.write([0x00, 0x27], 32); 209 | device.pause(30); 210 | commandHandler(); 211 | } 212 | 213 | function returnTotalLeds(data) { 214 | LEDCount = data[2]; 215 | device.log("Device Total LED Count: " + LEDCount); 216 | device.pause(30); 217 | } 218 | 219 | function requestFirmwareType() { 220 | device.write([0x00, 0x28], 32); 221 | device.pause(30); 222 | commandHandler(); 223 | } 224 | 225 | function returnFirmwareType(data) { 226 | const FirmwareTypeByte = data[2]; 227 | 228 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) { 229 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 230 | } 231 | 232 | if(FirmwareTypeByte === MainlineQMKFirmware) { 233 | IsViaKeyboard = false; 234 | device.log("Firmware Type: Mainline"); 235 | } 236 | 237 | if(FirmwareTypeByte === VIAFirmware) { 238 | IsViaKeyboard = true; 239 | device.log("Firmware Type: VIA"); 240 | } 241 | 242 | device.pause(30); 243 | } 244 | 245 | function effectEnable() //Enable the SignalRGB Effect Mode 246 | { 247 | device.write([0x00, 0x25], 32); 248 | device.pause(30); 249 | } 250 | 251 | function effectDisable() //Revert to Hardware Mode 252 | { 253 | device.write([0x00, 0x26], 32); 254 | device.pause(30); 255 | } 256 | 257 | function createSolidColorArray(color) { 258 | const rgbdata = new Array(vKeys.length * 3).fill(0); 259 | 260 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 261 | const iLedIdx = vKeys[iIdx] * 3; 262 | rgbdata[iLedIdx] = color[0]; 263 | rgbdata[iLedIdx+1] = color[1]; 264 | rgbdata[iLedIdx+2] = color[2]; 265 | } 266 | 267 | return rgbdata; 268 | } 269 | 270 | function grabColors(overrideColor) { 271 | if(overrideColor) { 272 | return createSolidColorArray(hexToRgb(overrideColor)); 273 | } else if (LightingMode === "Forced") { 274 | return createSolidColorArray(hexToRgb(forcedColor)); 275 | } 276 | 277 | const rgbdata = new Array(vKeys.length * 3).fill(0); 278 | 279 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 280 | const iPxX = vKeyPositions[iIdx][0]; 281 | const iPxY = vKeyPositions[iIdx][1]; 282 | const color = device.color(iPxX, iPxY); 283 | 284 | const iLedIdx = vKeys[iIdx] * 3; 285 | rgbdata[iLedIdx] = color[0]; 286 | rgbdata[iLedIdx+1] = color[1]; 287 | rgbdata[iLedIdx+2] = color[2]; 288 | } 289 | 290 | return rgbdata; 291 | } 292 | 293 | function sendColors(overrideColor) { 294 | const rgbdata = grabColors(overrideColor); 295 | 296 | const LedsPerPacket = 9; 297 | let BytesSent = 0; 298 | let BytesLeft = rgbdata.length; 299 | 300 | while(BytesLeft > 0) { 301 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 302 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 303 | 304 | BytesLeft -= BytesToSend; 305 | BytesSent += BytesToSend; 306 | } 307 | } 308 | 309 | function StreamLightingData(StartLedIdx, RGBData) { 310 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 311 | device.write(packet, 33); 312 | } 313 | 314 | function hexToRgb(hex) { 315 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 316 | const colors = []; 317 | colors[0] = parseInt(result[1], 16); 318 | colors[1] = parseInt(result[2], 16); 319 | colors[2] = parseInt(result[3], 16); 320 | 321 | return colors; 322 | } 323 | 324 | export function Validate(endpoint) { 325 | return endpoint.interface === 1; 326 | } 327 | 328 | export function Image() { 329 | return ""; 330 | } -------------------------------------------------------------------------------- /Massdrop/Massdrop_CTRL_QMK_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "Massdrop CTRL QMK Keyboard"; } 2 | export function Version() { return "1.1.2"; } 3 | export function VendorId() { return 0x04d8; } 4 | export function ProductId() { return 0xEED2; } 5 | export function Publisher() { return "WhirlwindFX"; } 6 | export function Documentation() { return "qmk/drop-ctrl"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [19, 8]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() 18 | { 19 | return [ 20 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 21 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 22 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 23 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 24 | ]; 25 | } 26 | 27 | //Plugin Version: Built for Protocol V1.0.6 28 | 29 | const vKeys = 30 | [ 31 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 32 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33 | 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 34 | 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 35 | 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 36 | 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 37 | 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118 38 | ]; 39 | const vKeyNames = 40 | [ 41 | "Esc", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "Print Screen", "Scroll Lock", "Pause Break", 42 | "`", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", "Insert", "Home", "Page Up", 43 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", "Del", "End", "Page Down", 44 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter", 45 | "Left Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Right Shift", "Up Arrow", 46 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Alt", "Fn", "Menu", "Right Ctrl", "Left Arrow", "Down Arrow", "Right Arrow", 47 | "UnderGlow1", "UnderGlow2", "UnderGlow3", "UnderGlow4", "UnderGlow5", "UnderGlow6", "UnderGlow7", "UnderGlow8", "UnderGlow9", "UnderGlow10", "UnderGlow11", "UnderGlow12", "Underglow13", 48 | "UnderGlow14", "UnderGlow15", "UnderGlow16", "UnderGlow17", "UnderGlow18", "Underglow19", "Underglow20", "Underglow21", "Underglow22", "Underglow23", "Underglow24", "Underglow25", "Underglow26", "Underglow27", "Underglow28", "Underglow29", "Underglow30", "Underglow31", "Underglow32", 49 | ]; 50 | 51 | const vKeyPositions = 52 | [ 53 | [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], [15, 0], [16, 1], [17, 1], 54 | [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [12, 2], [13, 2], [14, 2], [15, 1], [16, 2], [17, 2], 55 | [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [11, 3], [12, 3], [13, 3], [14, 3], [15, 2], [16, 3], [17, 3], 56 | [1, 4], [2, 4], [3, 4], [4, 4], [5, 4], [6, 4], [7, 4], [8, 4], [9, 4], [10, 4], [11, 4], [12, 4], [13, 4], 57 | [1, 5], [2, 5], [3, 5], [4, 5], [5, 5], [6, 5], [7, 5], [8, 5], [9, 5], [10, 5], [11, 5], [12, 5], [16, 5], 58 | [1, 6], [2, 6], [3, 6], [7, 6], [11, 6], [12, 6], [13, 6], [14, 6], [15, 6], [16, 6], [17, 6], 59 | [18, 7], [16, 7], [14, 7], [12, 7], [11, 7], [10, 7], [9, 7], [7, 7], [6, 7], [5, 7], [4, 7], [2, 7], [0, 7], [0, 4], [0, 3], [0, 2], [0, 0], [2, 0], [4, 0], [5, 0], [6, 0], [7, 0], [9, 0], [10, 0], [11, 0], [12, 0], [14, 0], [16, 0], [18, 0], [18, 2], [18, 3], [18, 4], 60 | ]; 61 | 62 | let LEDCount = 0; 63 | const FirmwareType = 2; 64 | 65 | export function LedNames() 66 | { 67 | return vKeyNames; 68 | } 69 | 70 | export function LedPositions() 71 | { 72 | return vKeyPositions; 73 | } 74 | 75 | export function Initialize() 76 | { 77 | ClearReadBuffer(); 78 | checkFirmwareType(); 79 | versionQMK(); 80 | versionSignalRGBProtocol(); 81 | uniqueIdentifier(); 82 | effectEnable(); 83 | totalLEDs(); 84 | } 85 | 86 | export function Render() 87 | { 88 | sendColors(); 89 | } 90 | 91 | export function Shutdown(SystemSuspending) 92 | { 93 | 94 | if(SystemSuspending) 95 | { 96 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 97 | } 98 | else 99 | { 100 | if (shutdownMode === "SignalRGB") 101 | { 102 | sendColors(shutdownColor); 103 | } 104 | else 105 | { 106 | effectDisable(); 107 | } 108 | } 109 | //vKeysArrayCount(); // For debugging array counts 110 | 111 | } 112 | 113 | function checkFirmwareType() 114 | { 115 | const packet = []; 116 | packet[0] = 0x00; 117 | packet[1] = 0x28; 118 | 119 | device.write(packet, 32); 120 | 121 | const returnpacket = device.read(packet, 32); 122 | const FirmwareTypeByte = returnpacket[2]; 123 | 124 | if(FirmwareTypeByte !== 1 || FirmwareTypeByte !== 2) 125 | { 126 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 127 | } 128 | 129 | device.log("Firmware Type: " + FirmwareTypeByte); 130 | device.pause(30); 131 | } 132 | 133 | function ClearReadBuffer(timeout = 10) //Clear Read buffer to get correct values out of our read functions 134 | { 135 | let count = 0; 136 | const readCounts = []; 137 | 138 | while(device.getLastReadSize() > 0) 139 | { 140 | device.read([0x00], 32, timeout); 141 | count++; 142 | readCounts.push(device.getLastReadSize()); 143 | } 144 | } 145 | 146 | function versionQMK() //Check the version of QMK Firmware that the keyboard is running 147 | { 148 | const packet = []; 149 | packet[0] = 0x00; 150 | packet[1] = 0x21; 151 | 152 | device.write(packet, 32); 153 | 154 | const returnpacket = device.read(packet, 32); 155 | const QMKVersionByte1 = returnpacket[2]; 156 | const QMKVersionByte2 = returnpacket[3]; 157 | const QMKVersionByte3 = returnpacket[4]; 158 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 159 | device.pause(30); 160 | } 161 | 162 | function versionSignalRGBProtocol() //Grab the version of the SignalRGB Protocol the keyboard is running 163 | { 164 | const packet = []; 165 | packet[0] = 0x00; 166 | packet[1] = 0x22; 167 | 168 | device.write(packet, 32); 169 | 170 | const returnpacket = device.read(packet, 32); 171 | const ProtocolVersionByte1 = returnpacket[2]; 172 | const ProtocolVersionByte2 = returnpacket[3]; 173 | const ProtocolVersionByte3 = returnpacket[4]; 174 | device.log("SignalRGB Protocol Version: " + ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3); 175 | device.pause(30); 176 | } 177 | 178 | function uniqueIdentifier() //Grab the unique identifier for this keyboard model 179 | { 180 | const packet = []; 181 | packet[0] = 0x00; 182 | packet[1] = 0x23; 183 | 184 | device.write(packet, 32); 185 | 186 | const returnpacket = device.read(packet, 32); 187 | const UniqueIdentifierByte1 = returnpacket[2]; 188 | const UniqueIdentifierByte2 = returnpacket[3]; 189 | const UniqueIdentifierByte3 = returnpacket[4]; 190 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 191 | device.pause(30); 192 | } 193 | 194 | function totalLEDs() //Calculate total number of LEDs 195 | { 196 | const packet = []; 197 | packet[0] = 0x00; 198 | packet[1] = 0x27; 199 | 200 | device.write(packet, 32); 201 | 202 | const returnpacket = device.read(packet, 33); 203 | LEDCount = returnpacket[2]; 204 | device.log("Device Total LED Count: " + LEDCount); 205 | } 206 | 207 | function effectEnable() //Enable the SignalRGB Effect Mode 208 | { 209 | const packet = []; 210 | packet[0] = 0x00; 211 | packet[1] = 0x25; 212 | 213 | device.write(packet, 32); 214 | device.pause(30); 215 | } 216 | 217 | function effectDisable() //Revert to Hardware Mode 218 | { 219 | const packet = []; 220 | packet[0] = 0x00; 221 | packet[1] = 0x26; 222 | 223 | device.write(packet, 32); 224 | } 225 | 226 | function createSolidColorArray(color) 227 | { 228 | const rgbdata = new Array(vKeys.length * 3).fill(0); 229 | 230 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 231 | { 232 | const iLedIdx = vKeys[iIdx] * 3; 233 | rgbdata[iLedIdx] = color[0]; 234 | rgbdata[iLedIdx+1] = color[1]; 235 | rgbdata[iLedIdx+2] = color[2]; 236 | } 237 | 238 | return rgbdata; 239 | } 240 | 241 | function grabColors(overrideColor) 242 | { 243 | if(overrideColor) 244 | { 245 | return createSolidColorArray(hexToRgb(overrideColor)); 246 | } 247 | else if (LightingMode === "Forced") 248 | { 249 | return createSolidColorArray(hexToRgb(forcedColor)); 250 | } 251 | 252 | const rgbdata = new Array(vKeys.length * 3).fill(0); 253 | 254 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 255 | { 256 | const iPxX = vKeyPositions[iIdx][0]; 257 | const iPxY = vKeyPositions[iIdx][1]; 258 | let color = device.color(iPxX, iPxY); 259 | 260 | const iLedIdx = vKeys[iIdx] * 3; 261 | rgbdata[iLedIdx] = color[0]; 262 | rgbdata[iLedIdx+1] = color[1]; 263 | rgbdata[iLedIdx+2] = color[2]; 264 | } 265 | 266 | return rgbdata; 267 | } 268 | 269 | function sendColors(overrideColor) 270 | { 271 | const rgbdata = grabColors(overrideColor); 272 | 273 | const LedsPerPacket = 9; 274 | let BytesSent = 0; 275 | let BytesLeft = rgbdata.length; 276 | 277 | while(BytesLeft > 0) 278 | { 279 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 280 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 281 | 282 | BytesLeft -= BytesToSend; 283 | BytesSent += BytesToSend; 284 | } 285 | } 286 | 287 | function StreamLightingData(StartLedIdx, RGBData) 288 | { 289 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 290 | device.write(packet, 33); 291 | } 292 | 293 | function hexToRgb(hex) 294 | { 295 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 296 | const colors = []; 297 | colors[0] = parseInt(result[1], 16); 298 | colors[1] = parseInt(result[2], 16); 299 | colors[2] = parseInt(result[3], 16); 300 | 301 | return colors; 302 | } 303 | 304 | export function Validate(endpoint) 305 | { 306 | return endpoint.interface === 1; 307 | } 308 | 309 | export function ImageUrl() 310 | { 311 | return "https://marketplace.signalrgb.com/devices/brands/massdrop/keyboards/ctrl.png"; 312 | } -------------------------------------------------------------------------------- /Keychron/V Series/Standard/Keychron_V4_QMK_ISO_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "Keychron V4 QMK ISO Keyboard"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x3434; } 4 | export function ProductId() { return 0x0342; } 5 | export function Publisher() { return "WhirlwindFX"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [14, 5]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() { 18 | return [ 19 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 20 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#000000"}, 21 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 22 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 23 | ]; 24 | } 25 | 26 | //Plugin Version: Built for Protocol V1.0.6 27 | 28 | const vKeys = [ 29 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, //14 30 | 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 40, //14 31 | 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, //13 32 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, //13 33 | 54, 55, 56, 57, 58, 59, 60, 61 //8 34 | 35 | ]; 36 | 37 | const vKeyNames = [ 38 | "Esc", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", //14 39 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "Enter", //14 40 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "#", //13 41 | "Left Shift", "\|", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Right Shift", //13 42 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Alt", "Menu", "Fn", "Ctrl" //8 43 | ]; 44 | 45 | const vKeyPositions = [ 46 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], //14 47 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], //14 48 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [13, 2], //13 49 | [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [11, 3], [13, 3], //13 50 | [0, 4], [1, 4], [2, 4], [6, 4], [10, 4], [11, 4], [12, 4], [13, 4] //8 51 | ]; 52 | 53 | let LEDCount = 0; 54 | let IsViaKeyboard = false; 55 | const MainlineQMKFirmware = 1; 56 | const VIAFirmware = 2; 57 | const PluginProtocolVersion = "1.0.6"; 58 | 59 | export function LedNames() { 60 | return vKeyNames; 61 | } 62 | 63 | export function LedPositions() { 64 | return vKeyPositions; 65 | } 66 | 67 | export function vKeysArrayCount() { 68 | device.log('vKeys ' + vKeys.length); 69 | device.log('vKeyNames ' + vKeyNames.length); 70 | device.log('vKeyPositions ' + vKeyPositions.length); 71 | } 72 | 73 | export function Initialize() { 74 | requestFirmwareType(); 75 | requestQMKVersion(); 76 | requestSignalRGBProtocolVersion(); 77 | requestUniqueIdentifier(); 78 | requestTotalLeds(); 79 | effectEnable(); 80 | 81 | } 82 | 83 | export function Render() { 84 | sendColors(); 85 | } 86 | 87 | export function Shutdown(SystemSuspending) { 88 | 89 | if(SystemSuspending) { 90 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 91 | } else { 92 | if (shutdownMode === "SignalRGB") { 93 | sendColors(shutdownColor); 94 | } else { 95 | effectDisable(); 96 | } 97 | } 98 | 99 | vKeysArrayCount(); // For debugging array counts 100 | 101 | } 102 | 103 | function commandHandler() { 104 | const readCounts = []; 105 | 106 | do { 107 | const returnpacket = device.read([0x00], 32, 10); 108 | processCommands(returnpacket); 109 | 110 | readCounts.push(device.getLastReadSize()); 111 | 112 | // Extra Read to throw away empty packets from Via 113 | // Via always sends a second packet with the same Command Id. 114 | if(IsViaKeyboard) { 115 | device.read([0x00], 32, 10); 116 | } 117 | } 118 | while(device.getLastReadSize() > 0); 119 | 120 | } 121 | 122 | function processCommands(data) { 123 | switch(data[1]) { 124 | case 0x21: 125 | returnQMKVersion(data); 126 | break; 127 | case 0x22: 128 | returnSignalRGBProtocolVersion(data); 129 | break; 130 | case 0x23: 131 | returnUniqueIdentifier(data); 132 | break; 133 | case 0x24: 134 | sendColors(); 135 | break; 136 | case 0x27: 137 | returnTotalLeds(data); 138 | break; 139 | case 0x28: 140 | returnFirmwareType(data); 141 | break; 142 | } 143 | } 144 | 145 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 146 | { 147 | device.write([0x00, 0x21], 32); 148 | device.pause(30); 149 | commandHandler(); 150 | } 151 | 152 | function returnQMKVersion(data) { 153 | const QMKVersionByte1 = data[2]; 154 | const QMKVersionByte2 = data[3]; 155 | const QMKVersionByte3 = data[4]; 156 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 157 | device.log("QMK SRGB Plugin Version: "+ Version()); 158 | device.pause(30); 159 | } 160 | 161 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 162 | { 163 | device.write([0x00, 0x22], 32); 164 | device.pause(30); 165 | commandHandler(); 166 | } 167 | 168 | function returnSignalRGBProtocolVersion(data) { 169 | const ProtocolVersionByte1 = data[2]; 170 | const ProtocolVersionByte2 = data[3]; 171 | const ProtocolVersionByte3 = data[4]; 172 | 173 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 174 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 175 | 176 | 177 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) { 178 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 179 | } 180 | 181 | device.pause(30); 182 | } 183 | 184 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 185 | { 186 | if(device.write([0x00, 0x23], 32) === -1) { 187 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 188 | } 189 | 190 | device.pause(30); 191 | commandHandler(); 192 | } 193 | 194 | 195 | function returnUniqueIdentifier(data) { 196 | const UniqueIdentifierByte1 = data[2]; 197 | const UniqueIdentifierByte2 = data[3]; 198 | const UniqueIdentifierByte3 = data[4]; 199 | 200 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) { 201 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 202 | } 203 | 204 | device.pause(30); 205 | } 206 | 207 | function requestTotalLeds() //Calculate total number of LEDs 208 | { 209 | device.write([0x00, 0x27], 32); 210 | device.pause(30); 211 | commandHandler(); 212 | } 213 | 214 | function returnTotalLeds(data) { 215 | LEDCount = data[2]; 216 | device.log("Device Total LED Count: " + LEDCount); 217 | device.pause(30); 218 | } 219 | 220 | function requestFirmwareType() { 221 | device.write([0x00, 0x28], 32); 222 | device.pause(30); 223 | commandHandler(); 224 | } 225 | 226 | function returnFirmwareType(data) { 227 | const FirmwareTypeByte = data[2]; 228 | 229 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) { 230 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 231 | } 232 | 233 | if(FirmwareTypeByte === MainlineQMKFirmware) { 234 | IsViaKeyboard = false; 235 | device.log("Firmware Type: Mainline"); 236 | } 237 | 238 | if(FirmwareTypeByte === VIAFirmware) { 239 | IsViaKeyboard = true; 240 | device.log("Firmware Type: VIA"); 241 | } 242 | 243 | device.pause(30); 244 | } 245 | 246 | function effectEnable() //Enable the SignalRGB Effect Mode 247 | { 248 | device.write([0x00, 0x25], 32); 249 | device.pause(30); 250 | } 251 | 252 | function effectDisable() //Revert to Hardware Mode 253 | { 254 | device.write([0x00, 0x26], 32); 255 | device.pause(30); 256 | } 257 | 258 | function createSolidColorArray(color) { 259 | const rgbdata = new Array(vKeys.length * 3).fill(0); 260 | 261 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 262 | const iLedIdx = vKeys[iIdx] * 3; 263 | rgbdata[iLedIdx] = color[0]; 264 | rgbdata[iLedIdx+1] = color[1]; 265 | rgbdata[iLedIdx+2] = color[2]; 266 | } 267 | 268 | return rgbdata; 269 | } 270 | 271 | function grabColors(overrideColor) { 272 | if(overrideColor) { 273 | return createSolidColorArray(hexToRgb(overrideColor)); 274 | } else if (LightingMode === "Forced") { 275 | return createSolidColorArray(hexToRgb(forcedColor)); 276 | } 277 | 278 | const rgbdata = new Array(vKeys.length * 3).fill(0); 279 | 280 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 281 | const iPxX = vKeyPositions[iIdx][0]; 282 | const iPxY = vKeyPositions[iIdx][1]; 283 | const color = device.color(iPxX, iPxY); 284 | 285 | const iLedIdx = vKeys[iIdx] * 3; 286 | rgbdata[iLedIdx] = color[0]; 287 | rgbdata[iLedIdx+1] = color[1]; 288 | rgbdata[iLedIdx+2] = color[2]; 289 | } 290 | 291 | return rgbdata; 292 | } 293 | 294 | function sendColors(overrideColor) { 295 | const rgbdata = grabColors(overrideColor); 296 | 297 | const LedsPerPacket = 9; 298 | let BytesSent = 0; 299 | let BytesLeft = rgbdata.length; 300 | 301 | while(BytesLeft > 0) { 302 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 303 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 304 | 305 | BytesLeft -= BytesToSend; 306 | BytesSent += BytesToSend; 307 | } 308 | } 309 | 310 | function StreamLightingData(StartLedIdx, RGBData) { 311 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 312 | device.write(packet, 33); 313 | } 314 | 315 | function hexToRgb(hex) { 316 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 317 | const colors = []; 318 | colors[0] = parseInt(result[1], 16); 319 | colors[1] = parseInt(result[2], 16); 320 | colors[2] = parseInt(result[3], 16); 321 | 322 | return colors; 323 | } 324 | 325 | export function Validate(endpoint) { 326 | return endpoint.interface === 1; 327 | } 328 | 329 | export function Image() { 330 | return ""; 331 | } -------------------------------------------------------------------------------- /Monsgeek/Monsgeek_M7_QMK_ANSI_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "MonsGeek M7 QMK Keyboard"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x0021; } 4 | export function ProductId() { return 0x001e; } 5 | export function Publisher() { return "Dudleydogg"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [16, 5]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() { 18 | return [ 19 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 20 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#000000"}, 21 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 22 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 23 | ]; 24 | } 25 | 26 | //Plugin Version: Built for Protocol V1.0.6 27 | 28 | const vKeys = [ 29 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 30 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 31 | 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 32 | 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 33 | 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 34 | ]; 35 | 36 | const vKeyNames = [ 37 | "Esc", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", "Insert", "Page Up", //16 38 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", "Del", "Page Down", //16 39 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter", //13 40 | "Left Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Right Shift", "Up Arrow", //13 41 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Alt", "Fn", "Right Ctrl", "Left Arrow", "Down Arrow", "Right Arrow", //10 42 | ]; 43 | 44 | const vKeyPositions = [ 45 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], [14, 0], [15, 0], 46 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], [14, 1], [15, 1], 47 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [13, 2], 48 | [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [13, 3], [14, 3], 49 | [0, 4], [1, 4], [2, 4], [5, 4], [9, 4], [10, 4], [11, 4], [13, 4], [14, 4], [15, 4], 50 | ]; 51 | 52 | 53 | 54 | let LEDCount = 0; 55 | let IsViaKeyboard = false; 56 | const MainlineQMKFirmware = 1; 57 | const VIAFirmware = 2; 58 | const PluginProtocolVersion = "1.0.6"; 59 | 60 | export function LedNames() { 61 | return vKeyNames; 62 | } 63 | 64 | export function LedPositions() { 65 | return vKeyPositions; 66 | } 67 | 68 | export function vKeysArrayCount() { 69 | device.log('vKeys ' + vKeys.length); 70 | device.log('vKeyNames ' + vKeyNames.length); 71 | device.log('vKeyPositions ' + vKeyPositions.length); 72 | } 73 | 74 | export function Initialize() { 75 | requestFirmwareType(); 76 | requestQMKVersion(); 77 | requestSignalRGBProtocolVersion(); 78 | requestUniqueIdentifier(); 79 | requestTotalLeds(); 80 | effectEnable(); 81 | 82 | } 83 | 84 | export function Render() { 85 | sendColors(); 86 | } 87 | 88 | export function Shutdown(SystemSuspending) { 89 | 90 | if(SystemSuspending) { 91 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 92 | } else { 93 | if (shutdownMode === "SignalRGB") { 94 | sendColors(shutdownColor); 95 | } else { 96 | effectDisable(); 97 | } 98 | } 99 | 100 | vKeysArrayCount(); // For debugging array counts 101 | 102 | } 103 | 104 | function commandHandler() { 105 | const readCounts = []; 106 | 107 | do { 108 | const returnpacket = device.read([0x00], 32, 10); 109 | processCommands(returnpacket); 110 | 111 | readCounts.push(device.getLastReadSize()); 112 | 113 | // Extra Read to throw away empty packets from Via 114 | // Via always sends a second packet with the same Command Id. 115 | if(IsViaKeyboard) { 116 | device.read([0x00], 32, 10); 117 | } 118 | } 119 | while(device.getLastReadSize() > 0); 120 | 121 | } 122 | 123 | function processCommands(data) { 124 | switch(data[1]) { 125 | case 0x21: 126 | returnQMKVersion(data); 127 | break; 128 | case 0x22: 129 | returnSignalRGBProtocolVersion(data); 130 | break; 131 | case 0x23: 132 | returnUniqueIdentifier(data); 133 | break; 134 | case 0x24: 135 | sendColors(); 136 | break; 137 | case 0x27: 138 | returnTotalLeds(data); 139 | break; 140 | case 0x28: 141 | returnFirmwareType(data); 142 | break; 143 | } 144 | } 145 | 146 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 147 | { 148 | device.write([0x00, 0x21], 32); 149 | device.pause(30); 150 | commandHandler(); 151 | } 152 | 153 | function returnQMKVersion(data) { 154 | const QMKVersionByte1 = data[2]; 155 | const QMKVersionByte2 = data[3]; 156 | const QMKVersionByte3 = data[4]; 157 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 158 | device.log("QMK SRGB Plugin Version: "+ Version()); 159 | device.pause(30); 160 | } 161 | 162 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 163 | { 164 | device.write([0x00, 0x22], 32); 165 | device.pause(30); 166 | commandHandler(); 167 | } 168 | 169 | function returnSignalRGBProtocolVersion(data) { 170 | const ProtocolVersionByte1 = data[2]; 171 | const ProtocolVersionByte2 = data[3]; 172 | const ProtocolVersionByte3 = data[4]; 173 | 174 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 175 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 176 | 177 | 178 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) { 179 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 180 | } 181 | 182 | device.pause(30); 183 | } 184 | 185 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 186 | { 187 | if(device.write([0x00, 0x23], 32) === -1) { 188 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 189 | } 190 | 191 | device.pause(30); 192 | commandHandler(); 193 | } 194 | 195 | 196 | function returnUniqueIdentifier(data) { 197 | const UniqueIdentifierByte1 = data[2]; 198 | const UniqueIdentifierByte2 = data[3]; 199 | const UniqueIdentifierByte3 = data[4]; 200 | 201 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) { 202 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 203 | } 204 | 205 | device.pause(30); 206 | } 207 | 208 | function requestTotalLeds() //Calculate total number of LEDs 209 | { 210 | device.write([0x00, 0x27], 32); 211 | device.pause(30); 212 | commandHandler(); 213 | } 214 | 215 | function returnTotalLeds(data) { 216 | LEDCount = data[2]; 217 | device.log("Device Total LED Count: " + LEDCount); 218 | device.pause(30); 219 | } 220 | 221 | function requestFirmwareType() { 222 | device.write([0x00, 0x28], 32); 223 | device.pause(30); 224 | commandHandler(); 225 | } 226 | 227 | function returnFirmwareType(data) { 228 | const FirmwareTypeByte = data[2]; 229 | 230 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) { 231 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 232 | } 233 | 234 | if(FirmwareTypeByte === MainlineQMKFirmware) { 235 | IsViaKeyboard = false; 236 | device.log("Firmware Type: Mainline"); 237 | } 238 | 239 | if(FirmwareTypeByte === VIAFirmware) { 240 | IsViaKeyboard = true; 241 | device.log("Firmware Type: VIA"); 242 | } 243 | 244 | device.pause(30); 245 | } 246 | 247 | function effectEnable() //Enable the SignalRGB Effect Mode 248 | { 249 | device.write([0x00, 0x25], 32); 250 | device.pause(30); 251 | } 252 | 253 | function effectDisable() //Revert to Hardware Mode 254 | { 255 | device.write([0x00, 0x26], 32); 256 | device.pause(30); 257 | } 258 | 259 | function createSolidColorArray(color) { 260 | const rgbdata = new Array(vKeys.length * 3).fill(0); 261 | 262 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 263 | const iLedIdx = vKeys[iIdx] * 3; 264 | rgbdata[iLedIdx] = color[0]; 265 | rgbdata[iLedIdx+1] = color[1]; 266 | rgbdata[iLedIdx+2] = color[2]; 267 | } 268 | 269 | return rgbdata; 270 | } 271 | 272 | function grabColors(overrideColor) { 273 | if(overrideColor) { 274 | return createSolidColorArray(hexToRgb(overrideColor)); 275 | } else if (LightingMode === "Forced") { 276 | return createSolidColorArray(hexToRgb(forcedColor)); 277 | } 278 | 279 | const rgbdata = new Array(vKeys.length * 3).fill(0); 280 | 281 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 282 | const iPxX = vKeyPositions[iIdx][0]; 283 | const iPxY = vKeyPositions[iIdx][1]; 284 | const color = device.color(iPxX, iPxY); 285 | 286 | const iLedIdx = vKeys[iIdx] * 3; 287 | rgbdata[iLedIdx] = color[0]; 288 | rgbdata[iLedIdx+1] = color[1]; 289 | rgbdata[iLedIdx+2] = color[2]; 290 | } 291 | 292 | return rgbdata; 293 | } 294 | 295 | function sendColors(overrideColor) { 296 | const rgbdata = grabColors(overrideColor); 297 | 298 | const LedsPerPacket = 9; 299 | let BytesSent = 0; 300 | let BytesLeft = rgbdata.length; 301 | 302 | while(BytesLeft > 0) { 303 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 304 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 305 | 306 | BytesLeft -= BytesToSend; 307 | BytesSent += BytesToSend; 308 | } 309 | } 310 | 311 | function StreamLightingData(StartLedIdx, RGBData) { 312 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 313 | device.write(packet, 33); 314 | } 315 | 316 | function hexToRgb(hex) { 317 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 318 | const colors = []; 319 | colors[0] = parseInt(result[1], 16); 320 | colors[1] = parseInt(result[2], 16); 321 | colors[2] = parseInt(result[3], 16); 322 | 323 | return colors; 324 | } 325 | 326 | export function Validate(endpoint) { 327 | return endpoint.interface === 1; 328 | } -------------------------------------------------------------------------------- /Swagkeys/SW_EAVE65.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "SW Eave65"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x4a16; } 4 | export function ProductId() { return 0x4a16; } 5 | export function Publisher() { return "SDx"; } 6 | export function Documentation(){ return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [15, 5]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() { 18 | return [ 19 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 20 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#000000"}, 21 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 22 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 23 | ]; 24 | } 25 | 26 | //Plugin Version: Built for Protocol V1.0.6 27 | 28 | const vKeys = [ 29 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //15 30 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, //15 31 | 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, //14 32 | 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, //14 33 | 58, 59, 60, 61, 62, 63, 64, 65, 66, //9 34 | ]; 35 | 36 | const vKeyNames = [ 37 | "Esc", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", "Home", //15 38 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", "PgUp", //15 39 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter", "PgDn", //14 40 | "Left Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Right Shift", "Up Arrow", "End", //14 41 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Alt", "Menu", "Left Arrow", "Down Arrow", "Right Arrow", //9 42 | ]; 43 | 44 | const vKeyPositions = [ 45 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], [14, 0], //15 46 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], [14, 1], //15 47 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [13, 2], [14, 2], //14 48 | [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [11, 3], [12, 3], [14, 3], //14 49 | [0, 4], [1, 4], [2, 4], [6, 4], [10, 4], [11, 4], [12, 4], [13, 4], [14, 4], //9 50 | ]; 51 | 52 | let LEDCount = 0; 53 | let IsViaKeyboard = false; 54 | const MainlineQMKFirmware = 1; 55 | const VIAFirmware = 2; 56 | const PluginProtocolVersion = "1.0.6"; 57 | 58 | export function LedNames() { 59 | return vKeyNames; 60 | } 61 | 62 | export function LedPositions() { 63 | return vKeyPositions; 64 | } 65 | 66 | export function vKeysArrayCount() { 67 | device.log('vKeys ' + vKeys.length); 68 | device.log('vKeyNames ' + vKeyNames.length); 69 | device.log('vKeyPositions ' + vKeyPositions.length); 70 | } 71 | 72 | export function Initialize() { 73 | requestFirmwareType(); 74 | requestQMKVersion(); 75 | requestSignalRGBProtocolVersion(); 76 | requestUniqueIdentifier(); 77 | requestTotalLeds(); 78 | effectEnable(); 79 | 80 | } 81 | 82 | export function Render() { 83 | sendColors(); 84 | } 85 | 86 | export function Shutdown(SystemSuspending) { 87 | 88 | if(SystemSuspending) { 89 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 90 | } else { 91 | if (shutdownMode === "SignalRGB") { 92 | sendColors(shutdownColor); 93 | } else { 94 | effectDisable(); 95 | } 96 | } 97 | 98 | vKeysArrayCount(); // For debugging array counts 99 | 100 | } 101 | 102 | function commandHandler() { 103 | const readCounts = []; 104 | 105 | do { 106 | const returnpacket = device.read([0x00], 32, 10); 107 | processCommands(returnpacket); 108 | 109 | readCounts.push(device.getLastReadSize()); 110 | 111 | // Extra Read to throw away empty packets from Via 112 | // Via always sends a second packet with the same Command Id. 113 | if(IsViaKeyboard) { 114 | device.read([0x00], 32, 10); 115 | } 116 | } 117 | while(device.getLastReadSize() > 0); 118 | 119 | } 120 | 121 | function processCommands(data) { 122 | switch(data[1]) { 123 | case 0x21: 124 | returnQMKVersion(data); 125 | break; 126 | case 0x22: 127 | returnSignalRGBProtocolVersion(data); 128 | break; 129 | case 0x23: 130 | returnUniqueIdentifier(data); 131 | break; 132 | case 0x24: 133 | sendColors(); 134 | break; 135 | case 0x27: 136 | returnTotalLeds(data); 137 | break; 138 | case 0x28: 139 | returnFirmwareType(data); 140 | break; 141 | } 142 | } 143 | 144 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 145 | { 146 | device.write([0x00, 0x21], 32); 147 | device.pause(30); 148 | commandHandler(); 149 | } 150 | 151 | function returnQMKVersion(data) { 152 | const QMKVersionByte1 = data[2]; 153 | const QMKVersionByte2 = data[3]; 154 | const QMKVersionByte3 = data[4]; 155 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 156 | device.log("QMK SRGB Plugin Version: "+ Version()); 157 | device.pause(30); 158 | } 159 | 160 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 161 | { 162 | device.write([0x00, 0x22], 32); 163 | device.pause(30); 164 | commandHandler(); 165 | } 166 | 167 | function returnSignalRGBProtocolVersion(data) { 168 | const ProtocolVersionByte1 = data[2]; 169 | const ProtocolVersionByte2 = data[3]; 170 | const ProtocolVersionByte3 = data[4]; 171 | 172 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 173 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 174 | 175 | 176 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) { 177 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 178 | } 179 | 180 | device.pause(30); 181 | } 182 | 183 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 184 | { 185 | if(device.write([0x00, 0x23], 32) === -1) { 186 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 187 | } 188 | 189 | device.pause(30); 190 | commandHandler(); 191 | } 192 | 193 | 194 | function returnUniqueIdentifier(data) { 195 | const UniqueIdentifierByte1 = data[2]; 196 | const UniqueIdentifierByte2 = data[3]; 197 | const UniqueIdentifierByte3 = data[4]; 198 | 199 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) { 200 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 201 | } 202 | 203 | device.pause(30); 204 | } 205 | 206 | function requestTotalLeds() //Calculate total number of LEDs 207 | { 208 | device.write([0x00, 0x27], 32); 209 | device.pause(30); 210 | commandHandler(); 211 | } 212 | 213 | function returnTotalLeds(data) { 214 | LEDCount = data[2]; 215 | device.log("Device Total LED Count: " + LEDCount); 216 | device.pause(30); 217 | } 218 | 219 | function requestFirmwareType() { 220 | device.write([0x00, 0x28], 32); 221 | device.pause(30); 222 | commandHandler(); 223 | } 224 | 225 | function returnFirmwareType(data) { 226 | const FirmwareTypeByte = data[2]; 227 | 228 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) { 229 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 230 | } 231 | 232 | if(FirmwareTypeByte === MainlineQMKFirmware) { 233 | IsViaKeyboard = false; 234 | device.log("Firmware Type: Mainline"); 235 | } 236 | 237 | if(FirmwareTypeByte === VIAFirmware) { 238 | IsViaKeyboard = true; 239 | device.log("Firmware Type: VIA"); 240 | } 241 | 242 | device.pause(30); 243 | } 244 | 245 | function effectEnable() //Enable the SignalRGB Effect Mode 246 | { 247 | device.write([0x00, 0x25], 32); 248 | device.pause(30); 249 | } 250 | 251 | function effectDisable() //Revert to Hardware Mode 252 | { 253 | device.write([0x00, 0x26], 32); 254 | device.pause(30); 255 | } 256 | 257 | function createSolidColorArray(color) { 258 | const rgbdata = new Array(vKeys.length * 3).fill(0); 259 | 260 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 261 | const iLedIdx = vKeys[iIdx] * 3; 262 | rgbdata[iLedIdx] = color[0]; 263 | rgbdata[iLedIdx+1] = color[1]; 264 | rgbdata[iLedIdx+2] = color[2]; 265 | } 266 | 267 | return rgbdata; 268 | } 269 | 270 | function grabColors(overrideColor) { 271 | if(overrideColor) { 272 | return createSolidColorArray(hexToRgb(overrideColor)); 273 | } else if (LightingMode === "Forced") { 274 | return createSolidColorArray(hexToRgb(forcedColor)); 275 | } 276 | 277 | const rgbdata = new Array(vKeys.length * 3).fill(0); 278 | 279 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 280 | const iPxX = vKeyPositions[iIdx][0]; 281 | const iPxY = vKeyPositions[iIdx][1]; 282 | const color = device.color(iPxX, iPxY); 283 | 284 | const iLedIdx = vKeys[iIdx] * 3; 285 | rgbdata[iLedIdx] = color[0]; 286 | rgbdata[iLedIdx+1] = color[1]; 287 | rgbdata[iLedIdx+2] = color[2]; 288 | } 289 | 290 | return rgbdata; 291 | } 292 | 293 | function sendColors(overrideColor) { 294 | const rgbdata = grabColors(overrideColor); 295 | 296 | const LedsPerPacket = 9; 297 | let BytesSent = 0; 298 | let BytesLeft = rgbdata.length; 299 | 300 | while(BytesLeft > 0) { 301 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 302 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 303 | 304 | BytesLeft -= BytesToSend; 305 | BytesSent += BytesToSend; 306 | } 307 | } 308 | 309 | function StreamLightingData(StartLedIdx, RGBData) { 310 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 311 | device.write(packet, 33); 312 | } 313 | 314 | function hexToRgb(hex) { 315 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 316 | const colors = []; 317 | colors[0] = parseInt(result[1], 16); 318 | colors[1] = parseInt(result[2], 16); 319 | colors[2] = parseInt(result[3], 16); 320 | 321 | return colors; 322 | } 323 | 324 | export function Validate(endpoint) { 325 | return endpoint.interface === 1; 326 | } 327 | 328 | export function Image() { 329 | return ""; 330 | } -------------------------------------------------------------------------------- /DZTech/DZTech-60RGB_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "DZTech ANSI DZ60RGB"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x445a; } 4 | export function ProductId() { return [0x1220, 0x1221]; } 5 | export function Publisher() { return "WhirlwindFX"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [14, 5]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() 18 | { 19 | return [ 20 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 21 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"000000"}, 22 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 23 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"009bde"}, 24 | ]; 25 | } 26 | 27 | //Plugin Version: Built for Protocol V1.0.6 28 | 29 | const vKeys = 30 | [ 31 | 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 32 | 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 33 | 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 34 | 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 35 | 60, 59, 58, 57, 56, 55, 54, 53 36 | ]; 37 | const vKeyNames = 38 | [ 39 | "`", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", 40 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", 41 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter", 42 | "Left Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Right Shift", 43 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Alt", "Menu", "Fn", "Right Ctrl" 44 | ]; 45 | 46 | const vKeyPositions = 47 | [ 48 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], 49 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], 50 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [13, 2], 51 | [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [11, 3], 52 | [0, 4], [1, 4], [2, 4], [5, 4], [9, 4], [10, 4], [11, 4], [13, 4] 53 | ]; 54 | 55 | let LEDCount = 0; 56 | let IsViaKeyboard = false; 57 | const MainlineQMKFirmware = 1; 58 | const VIAFirmware = 2; 59 | const PluginProtocolVersion = "1.0.6"; 60 | 61 | export function LedNames() 62 | { 63 | return vKeyNames; 64 | } 65 | 66 | export function LedPositions() 67 | { 68 | return vKeyPositions; 69 | } 70 | 71 | export function vKeysArrayCount() 72 | { 73 | device.log('vKeys ' + vKeys.length); 74 | device.log('vKeyNames ' + vKeyNames.length); 75 | device.log('vKeyPositions ' + vKeyPositions.length); 76 | } 77 | 78 | export function Initialize() 79 | { 80 | requestFirmwareType(); 81 | requestQMKVersion(); 82 | requestSignalRGBProtocolVersion(); 83 | requestUniqueIdentifier(); 84 | requestTotalLeds(); 85 | effectEnable(); 86 | 87 | } 88 | 89 | export function Render() 90 | { 91 | sendColors(); 92 | } 93 | 94 | export function Shutdown(SystemSuspending) 95 | { 96 | 97 | if(SystemSuspending) 98 | { 99 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 100 | } 101 | else 102 | { 103 | if (shutdownMode === "SignalRGB") 104 | { 105 | sendColors(shutdownColor); 106 | } 107 | else 108 | { 109 | effectDisable(); 110 | } 111 | } 112 | //vKeysArrayCount(); // For debugging array counts 113 | 114 | } 115 | 116 | function commandHandler() 117 | { 118 | const readCounts = []; 119 | 120 | do 121 | { 122 | const returnpacket = device.read([0x00], 32, 10); 123 | processCommands(returnpacket); 124 | 125 | readCounts.push(device.getLastReadSize()); 126 | 127 | // Extra Read to throw away empty packets from Via 128 | // Via always sends a second packet with the same Command Id. 129 | if(IsViaKeyboard) 130 | { 131 | device.read([0x00], 32, 10); 132 | } 133 | } 134 | while(device.getLastReadSize() > 0); 135 | 136 | } 137 | 138 | function processCommands(data) 139 | { 140 | switch(data[1]) 141 | { 142 | case 0x21: 143 | returnQMKVersion(data); 144 | break; 145 | case 0x22: 146 | returnSignalRGBProtocolVersion(data); 147 | break; 148 | case 0x23: 149 | returnUniqueIdentifier(data); 150 | break; 151 | case 0x24: 152 | sendColors(); 153 | break; 154 | case 0x27: 155 | returnTotalLeds(data); 156 | break; 157 | case 0x28: 158 | returnFirmwareType(data); 159 | break; 160 | } 161 | } 162 | 163 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 164 | { 165 | device.write([0x00, 0x21], 32); 166 | device.pause(30); 167 | commandHandler(); 168 | } 169 | 170 | function returnQMKVersion(data) 171 | { 172 | const QMKVersionByte1 = data[2]; 173 | const QMKVersionByte2 = data[3]; 174 | const QMKVersionByte3 = data[4]; 175 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 176 | device.log("QMK SRGB Plugin Version: "+ Version() ); 177 | device.pause(30); 178 | } 179 | 180 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 181 | { 182 | device.write([0x00, 0x22], 32); 183 | device.pause(30); 184 | commandHandler(); 185 | } 186 | 187 | function returnSignalRGBProtocolVersion(data) 188 | { 189 | const ProtocolVersionByte1 = data[2]; 190 | const ProtocolVersionByte2 = data[3]; 191 | const ProtocolVersionByte3 = data[4]; 192 | 193 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 194 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 195 | 196 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) 197 | { 198 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 199 | } 200 | 201 | device.pause(30); 202 | } 203 | 204 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 205 | { 206 | if(device.write([0x00, 0x23], 32) === -1) 207 | { 208 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 209 | } 210 | 211 | device.pause(30); 212 | commandHandler(); 213 | } 214 | 215 | function returnUniqueIdentifier(data) 216 | { 217 | const UniqueIdentifierByte1 = data[2]; 218 | const UniqueIdentifierByte2 = data[3]; 219 | const UniqueIdentifierByte3 = data[4]; 220 | 221 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) 222 | { 223 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 224 | } 225 | 226 | device.pause(30); 227 | } 228 | 229 | function requestTotalLeds() //Calculate total number of LEDs 230 | { 231 | device.write([0x00, 0x27], 32); 232 | device.pause(30); 233 | commandHandler(); 234 | } 235 | 236 | function returnTotalLeds(data) 237 | { 238 | LEDCount = data[2]; 239 | device.log("Device Total LED Count: " + LEDCount); 240 | device.pause(30); 241 | } 242 | 243 | function requestFirmwareType() 244 | { 245 | device.write([0x00, 0x28], 32); 246 | device.pause(30); 247 | commandHandler(); 248 | } 249 | 250 | function returnFirmwareType(data) 251 | { 252 | const FirmwareTypeByte = data[2]; 253 | 254 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) 255 | { 256 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 257 | } 258 | 259 | if(FirmwareTypeByte === MainlineQMKFirmware) 260 | { 261 | IsViaKeyboard = false; 262 | device.log("Firmware Type: Mainline"); 263 | } 264 | 265 | if(FirmwareTypeByte === VIAFirmware) 266 | { 267 | IsViaKeyboard = true; 268 | device.log("Firmware Type: VIA"); 269 | } 270 | 271 | device.pause(30); 272 | } 273 | 274 | function effectEnable() //Enable the SignalRGB Effect Mode 275 | { 276 | device.write([0x00, 0x25], 32); 277 | device.pause(30); 278 | } 279 | 280 | function effectDisable() //Revert to Hardware Mode 281 | { 282 | device.write([0x00, 0x26], 32); 283 | device.pause(30); 284 | } 285 | 286 | function createSolidColorArray(color) 287 | { 288 | const rgbdata = new Array(vKeys.length * 3).fill(0); 289 | 290 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 291 | { 292 | const iLedIdx = vKeys[iIdx] * 3; 293 | rgbdata[iLedIdx] = color[0]; 294 | rgbdata[iLedIdx+1] = color[1]; 295 | rgbdata[iLedIdx+2] = color[2]; 296 | } 297 | 298 | return rgbdata; 299 | } 300 | 301 | function grabColors(overrideColor) 302 | { 303 | if(overrideColor) 304 | { 305 | return createSolidColorArray(hexToRgb(overrideColor)); 306 | } 307 | else if (LightingMode === "Forced") 308 | { 309 | return createSolidColorArray(hexToRgb(forcedColor)); 310 | } 311 | 312 | const rgbdata = new Array(vKeys.length * 3).fill(0); 313 | 314 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 315 | { 316 | const iPxX = vKeyPositions[iIdx][0]; 317 | const iPxY = vKeyPositions[iIdx][1]; 318 | let color = device.color(iPxX, iPxY); 319 | 320 | const iLedIdx = vKeys[iIdx] * 3; 321 | rgbdata[iLedIdx] = color[0]; 322 | rgbdata[iLedIdx+1] = color[1]; 323 | rgbdata[iLedIdx+2] = color[2]; 324 | } 325 | 326 | return rgbdata; 327 | } 328 | 329 | function sendColors(overrideColor) 330 | { 331 | const rgbdata = grabColors(overrideColor); 332 | 333 | const LedsPerPacket = 9; 334 | let BytesSent = 0; 335 | let BytesLeft = rgbdata.length; 336 | 337 | while(BytesLeft > 0) 338 | { 339 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 340 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 341 | 342 | BytesLeft -= BytesToSend; 343 | BytesSent += BytesToSend; 344 | } 345 | } 346 | 347 | function StreamLightingData(StartLedIdx, RGBData) 348 | { 349 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 350 | device.write(packet, 33); 351 | } 352 | 353 | function hexToRgb(hex) 354 | { 355 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 356 | const colors = []; 357 | colors[0] = parseInt(result[1], 16); 358 | colors[1] = parseInt(result[2], 16); 359 | colors[2] = parseInt(result[3], 16); 360 | 361 | return colors; 362 | } 363 | 364 | export function Validate(endpoint) 365 | { 366 | return endpoint.interface === 1; 367 | } -------------------------------------------------------------------------------- /Keychron/Q Series/Pro/Keychron_Q2_Pro_QMK_ANSI_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "Keychron Q2 Pro ANSI Encoder"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x3434; } 4 | export function ProductId() { return 0x0620; } 5 | export function Publisher() { return "WhirlwindFX"; } 6 | export function Documentation(){ return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [15, 5]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() { 18 | return [ 19 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 20 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#000000"}, 21 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 22 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 23 | ]; 24 | } 25 | 26 | //Plugin Version: Built for Protocol V1.0.6 27 | 28 | const vKeys = [ 29 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, //14 30 | 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, //15 31 | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, //14 32 | 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, //13 33 | 56, 57, 58, 59, 60, 61, 62, 63, 64, 65 //10 34 | ]; 35 | 36 | const vKeyNames = [ 37 | "Esc", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", //14 38 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", "Del", //15 39 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter", "Home", //14 40 | "Left Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Right Shift", "Up Arrow", //13 41 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Alt", "Menu", "Apps", "Left Arrow", "Down Arrow", "Right Arrow", //10 42 | ]; 43 | 44 | const vKeyPositions = [ 45 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], //14 46 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], [14, 1], //15 47 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [12, 2], [14, 2], //14 48 | [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [11, 3], [12, 3], //13 49 | [0, 4], [1, 4], [2, 4], [6, 4], [9, 4], [10, 4], [11, 4], [12, 4], [13, 4], [14, 4], //10 50 | ]; 51 | 52 | let LEDCount = 0; 53 | let IsViaKeyboard = false; 54 | const MainlineQMKFirmware = 1; 55 | const VIAFirmware = 2; 56 | const PluginProtocolVersion = "1.0.6"; 57 | 58 | export function LedNames() { 59 | return vKeyNames; 60 | } 61 | 62 | export function LedPositions() { 63 | return vKeyPositions; 64 | } 65 | 66 | export function vKeysArrayCount() { 67 | device.log('vKeys ' + vKeys.length); 68 | device.log('vKeyNames ' + vKeyNames.length); 69 | device.log('vKeyPositions ' + vKeyPositions.length); 70 | } 71 | 72 | export function Initialize() { 73 | requestFirmwareType(); 74 | requestQMKVersion(); 75 | requestSignalRGBProtocolVersion(); 76 | requestUniqueIdentifier(); 77 | requestTotalLeds(); 78 | effectEnable(); 79 | 80 | } 81 | 82 | export function Render() { 83 | sendColors(); 84 | } 85 | 86 | export function Shutdown(SystemSuspending) { 87 | 88 | if(SystemSuspending) { 89 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 90 | } else { 91 | if (shutdownMode === "SignalRGB") { 92 | sendColors(shutdownColor); 93 | } else { 94 | effectDisable(); 95 | } 96 | } 97 | 98 | //vKeysArrayCount(); // For debugging array counts 99 | 100 | } 101 | 102 | function commandHandler() { 103 | const readCounts = []; 104 | 105 | do { 106 | const returnpacket = device.read([0x00], 32, 10); 107 | processCommands(returnpacket); 108 | 109 | readCounts.push(device.getLastReadSize()); 110 | 111 | // Extra Read to throw away empty packets from Via 112 | // Via always sends a second packet with the same Command Id. 113 | if(IsViaKeyboard) { 114 | device.read([0x00], 32, 10); 115 | } 116 | } 117 | while(device.getLastReadSize() > 0); 118 | 119 | } 120 | 121 | function processCommands(data) { 122 | switch(data[1]) { 123 | case 0x21: 124 | returnQMKVersion(data); 125 | break; 126 | case 0x22: 127 | returnSignalRGBProtocolVersion(data); 128 | break; 129 | case 0x23: 130 | returnUniqueIdentifier(data); 131 | break; 132 | case 0x24: 133 | sendColors(); 134 | break; 135 | case 0x27: 136 | returnTotalLeds(data); 137 | break; 138 | case 0x28: 139 | returnFirmwareType(data); 140 | break; 141 | } 142 | } 143 | 144 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 145 | { 146 | device.write([0x00, 0x21], 32); 147 | device.pause(30); 148 | commandHandler(); 149 | } 150 | 151 | function returnQMKVersion(data) { 152 | const QMKVersionByte1 = data[2]; 153 | const QMKVersionByte2 = data[3]; 154 | const QMKVersionByte3 = data[4]; 155 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 156 | device.log("QMK SRGB Plugin Version: "+ Version()); 157 | device.pause(30); 158 | } 159 | 160 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 161 | { 162 | device.write([0x00, 0x22], 32); 163 | device.pause(30); 164 | commandHandler(); 165 | } 166 | 167 | function returnSignalRGBProtocolVersion(data) { 168 | const ProtocolVersionByte1 = data[2]; 169 | const ProtocolVersionByte2 = data[3]; 170 | const ProtocolVersionByte3 = data[4]; 171 | 172 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 173 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 174 | 175 | 176 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) { 177 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 178 | } 179 | 180 | device.pause(30); 181 | } 182 | 183 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 184 | { 185 | if(device.write([0x00, 0x23], 32) === -1) { 186 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 187 | } 188 | 189 | device.pause(30); 190 | commandHandler(); 191 | } 192 | 193 | 194 | function returnUniqueIdentifier(data) { 195 | const UniqueIdentifierByte1 = data[2]; 196 | const UniqueIdentifierByte2 = data[3]; 197 | const UniqueIdentifierByte3 = data[4]; 198 | 199 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) { 200 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 201 | } 202 | 203 | device.pause(30); 204 | } 205 | 206 | function requestTotalLeds() //Calculate total number of LEDs 207 | { 208 | device.write([0x00, 0x27], 32); 209 | device.pause(30); 210 | commandHandler(); 211 | } 212 | 213 | function returnTotalLeds(data) { 214 | LEDCount = data[2]; 215 | device.log("Device Total LED Count: " + LEDCount); 216 | device.pause(30); 217 | } 218 | 219 | function requestFirmwareType() { 220 | device.write([0x00, 0x28], 32); 221 | device.pause(30); 222 | commandHandler(); 223 | } 224 | 225 | function returnFirmwareType(data) { 226 | const FirmwareTypeByte = data[2]; 227 | 228 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) { 229 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 230 | } 231 | 232 | if(FirmwareTypeByte === MainlineQMKFirmware) { 233 | IsViaKeyboard = false; 234 | device.log("Firmware Type: Mainline"); 235 | } 236 | 237 | if(FirmwareTypeByte === VIAFirmware) { 238 | IsViaKeyboard = true; 239 | device.log("Firmware Type: VIA"); 240 | } 241 | 242 | device.pause(30); 243 | } 244 | 245 | function effectEnable() //Enable the SignalRGB Effect Mode 246 | { 247 | device.write([0x00, 0x25], 32); 248 | device.pause(30); 249 | } 250 | 251 | function effectDisable() //Revert to Hardware Mode 252 | { 253 | device.write([0x00, 0x26], 32); 254 | device.pause(30); 255 | } 256 | 257 | function createSolidColorArray(color) { 258 | const rgbdata = new Array(vKeys.length * 3).fill(0); 259 | 260 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 261 | const iLedIdx = vKeys[iIdx] * 3; 262 | rgbdata[iLedIdx] = color[0]; 263 | rgbdata[iLedIdx+1] = color[1]; 264 | rgbdata[iLedIdx+2] = color[2]; 265 | } 266 | 267 | return rgbdata; 268 | } 269 | 270 | function grabColors(overrideColor) { 271 | if(overrideColor) { 272 | return createSolidColorArray(hexToRgb(overrideColor)); 273 | } else if (LightingMode === "Forced") { 274 | return createSolidColorArray(hexToRgb(forcedColor)); 275 | } 276 | 277 | const rgbdata = new Array(vKeys.length * 3).fill(0); 278 | 279 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 280 | const iPxX = vKeyPositions[iIdx][0]; 281 | const iPxY = vKeyPositions[iIdx][1]; 282 | const color = device.color(iPxX, iPxY); 283 | 284 | const iLedIdx = vKeys[iIdx] * 3; 285 | rgbdata[iLedIdx] = color[0]; 286 | rgbdata[iLedIdx+1] = color[1]; 287 | rgbdata[iLedIdx+2] = color[2]; 288 | } 289 | 290 | return rgbdata; 291 | } 292 | 293 | function sendColors(overrideColor) { 294 | const rgbdata = grabColors(overrideColor); 295 | 296 | const LedsPerPacket = 9; 297 | let BytesSent = 0; 298 | let BytesLeft = rgbdata.length; 299 | 300 | while(BytesLeft > 0) { 301 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 302 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 303 | 304 | BytesLeft -= BytesToSend; 305 | BytesSent += BytesToSend; 306 | } 307 | } 308 | 309 | function StreamLightingData(StartLedIdx, RGBData) { 310 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 311 | device.write(packet, 33); 312 | } 313 | 314 | function hexToRgb(hex) { 315 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 316 | const colors = []; 317 | colors[0] = parseInt(result[1], 16); 318 | colors[1] = parseInt(result[2], 16); 319 | colors[2] = parseInt(result[3], 16); 320 | 321 | return colors; 322 | } 323 | 324 | export function Validate(endpoint) { 325 | return endpoint.interface === 1; 326 | } 327 | 328 | export function Image() { 329 | return ""; 330 | } -------------------------------------------------------------------------------- /DZTech/DZTech-65RGB-V3_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "DZTech DZ65RGB V3"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x445a; } 4 | export function ProductId() { return 0x1424; } 5 | export function Publisher() { return "chewtoy9696"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [21, 6]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() 18 | { 19 | return [ 20 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 21 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"000000"}, 22 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 23 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"009bde"}, 24 | ]; 25 | } 26 | 27 | //Plugin Version: Built for Protocol V1.0.6 28 | 29 | const vKeys = 30 | [ 31 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 32 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 33 | 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 34 | 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 35 | 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 36 | ]; 37 | const vKeyNames = 38 | [ 39 | "`", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", "Del", 40 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", "Page Up", 41 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter", "Page Down", 42 | "Left Shift", "ISO_<", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Right Shift", "Up Arrow", "End", 43 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Alt", "Fn", "Right Ctrl", "Left Arrow", "Down Arrow", "Right Arrow" 44 | ]; 45 | 46 | const vKeyPositions = 47 | [ 48 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], [14, 0], 49 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], [14, 1], 50 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [12, 2], [13, 2], 51 | [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [11, 3], [12, 3], [13, 3], 52 | [0, 4], [1, 4], [2, 4], [3, 4], [4, 4], [5, 4], [6, 4], [7, 4], [8, 4], [9, 4], 53 | ]; 54 | 55 | let LEDCount = 0; 56 | let IsViaKeyboard = false; 57 | const MainlineQMKFirmware = 1; 58 | const VIAFirmware = 2; 59 | const PluginProtocolVersion = "1.0.6"; 60 | 61 | export function LedNames() 62 | { 63 | return vKeyNames; 64 | } 65 | 66 | export function LedPositions() 67 | { 68 | return vKeyPositions; 69 | } 70 | 71 | export function vKeysArrayCount() 72 | { 73 | device.log('vKeys ' + vKeys.length); 74 | device.log('vKeyNames ' + vKeyNames.length); 75 | device.log('vKeyPositions ' + vKeyPositions.length); 76 | } 77 | 78 | export function Initialize() 79 | { 80 | requestFirmwareType(); 81 | requestQMKVersion(); 82 | requestSignalRGBProtocolVersion(); 83 | requestUniqueIdentifier(); 84 | requestTotalLeds(); 85 | effectEnable(); 86 | 87 | } 88 | 89 | export function Render() 90 | { 91 | sendColors(); 92 | } 93 | 94 | export function Shutdown(SystemSuspending) 95 | { 96 | 97 | if(SystemSuspending) 98 | { 99 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 100 | } 101 | else 102 | { 103 | if (shutdownMode === "SignalRGB") 104 | { 105 | sendColors(shutdownColor); 106 | } 107 | else 108 | { 109 | effectDisable(); 110 | } 111 | } 112 | //vKeysArrayCount(); // For debugging array counts 113 | 114 | } 115 | 116 | function commandHandler() 117 | { 118 | const readCounts = []; 119 | 120 | do 121 | { 122 | const returnpacket = device.read([0x00], 32, 10); 123 | processCommands(returnpacket); 124 | 125 | readCounts.push(device.getLastReadSize()); 126 | 127 | // Extra Read to throw away empty packets from Via 128 | // Via always sends a second packet with the same Command Id. 129 | if(IsViaKeyboard) 130 | { 131 | device.read([0x00], 32, 10); 132 | } 133 | } 134 | while(device.getLastReadSize() > 0); 135 | 136 | } 137 | 138 | function processCommands(data) 139 | { 140 | switch(data[1]) 141 | { 142 | case 0x21: 143 | returnQMKVersion(data); 144 | break; 145 | case 0x22: 146 | returnSignalRGBProtocolVersion(data); 147 | break; 148 | case 0x23: 149 | returnUniqueIdentifier(data); 150 | break; 151 | case 0x24: 152 | sendColors(); 153 | break; 154 | case 0x27: 155 | returnTotalLeds(data); 156 | break; 157 | case 0x28: 158 | returnFirmwareType(data); 159 | break; 160 | } 161 | } 162 | 163 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 164 | { 165 | device.write([0x00, 0x21], 32); 166 | device.pause(30); 167 | commandHandler(); 168 | } 169 | 170 | function returnQMKVersion(data) 171 | { 172 | const QMKVersionByte1 = data[2]; 173 | const QMKVersionByte2 = data[3]; 174 | const QMKVersionByte3 = data[4]; 175 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 176 | device.log("QMK SRGB Plugin Version: "+ Version() ); 177 | device.pause(30); 178 | } 179 | 180 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 181 | { 182 | device.write([0x00, 0x22], 32); 183 | device.pause(30); 184 | commandHandler(); 185 | } 186 | 187 | function returnSignalRGBProtocolVersion(data) 188 | { 189 | const ProtocolVersionByte1 = data[2]; 190 | const ProtocolVersionByte2 = data[3]; 191 | const ProtocolVersionByte3 = data[4]; 192 | 193 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 194 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 195 | 196 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) 197 | { 198 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 199 | } 200 | 201 | device.pause(30); 202 | } 203 | 204 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 205 | { 206 | if(device.write([0x00, 0x23], 32) === -1) 207 | { 208 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 209 | } 210 | 211 | device.pause(30); 212 | commandHandler(); 213 | } 214 | 215 | function returnUniqueIdentifier(data) 216 | { 217 | const UniqueIdentifierByte1 = data[2]; 218 | const UniqueIdentifierByte2 = data[3]; 219 | const UniqueIdentifierByte3 = data[4]; 220 | 221 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) 222 | { 223 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 224 | } 225 | 226 | device.pause(30); 227 | } 228 | 229 | function requestTotalLeds() //Calculate total number of LEDs 230 | { 231 | device.write([0x00, 0x27], 32); 232 | device.pause(30); 233 | commandHandler(); 234 | } 235 | 236 | function returnTotalLeds(data) 237 | { 238 | LEDCount = data[2]; 239 | device.log("Device Total LED Count: " + LEDCount); 240 | device.pause(30); 241 | } 242 | 243 | function requestFirmwareType() 244 | { 245 | device.write([0x00, 0x28], 32); 246 | device.pause(30); 247 | commandHandler(); 248 | } 249 | 250 | function returnFirmwareType(data) 251 | { 252 | const FirmwareTypeByte = data[2]; 253 | 254 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) 255 | { 256 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 257 | } 258 | 259 | if(FirmwareTypeByte === MainlineQMKFirmware) 260 | { 261 | IsViaKeyboard = false; 262 | device.log("Firmware Type: Mainline"); 263 | } 264 | 265 | if(FirmwareTypeByte === VIAFirmware) 266 | { 267 | IsViaKeyboard = true; 268 | device.log("Firmware Type: VIA"); 269 | } 270 | 271 | device.pause(30); 272 | } 273 | 274 | function effectEnable() //Enable the SignalRGB Effect Mode 275 | { 276 | device.write([0x00, 0x25], 32); 277 | device.pause(30); 278 | } 279 | 280 | function effectDisable() //Revert to Hardware Mode 281 | { 282 | device.write([0x00, 0x26], 32); 283 | device.pause(30); 284 | } 285 | 286 | function createSolidColorArray(color) 287 | { 288 | const rgbdata = new Array(vKeys.length * 3).fill(0); 289 | 290 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 291 | { 292 | const iLedIdx = vKeys[iIdx] * 3; 293 | rgbdata[iLedIdx] = color[0]; 294 | rgbdata[iLedIdx+1] = color[1]; 295 | rgbdata[iLedIdx+2] = color[2]; 296 | } 297 | 298 | return rgbdata; 299 | } 300 | 301 | function grabColors(overrideColor) 302 | { 303 | if(overrideColor) 304 | { 305 | return createSolidColorArray(hexToRgb(overrideColor)); 306 | } 307 | else if (LightingMode === "Forced") 308 | { 309 | return createSolidColorArray(hexToRgb(forcedColor)); 310 | } 311 | 312 | const rgbdata = new Array(vKeys.length * 3).fill(0); 313 | 314 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 315 | { 316 | const iPxX = vKeyPositions[iIdx][0]; 317 | const iPxY = vKeyPositions[iIdx][1]; 318 | let color = device.color(iPxX, iPxY); 319 | 320 | const iLedIdx = vKeys[iIdx] * 3; 321 | rgbdata[iLedIdx] = color[0]; 322 | rgbdata[iLedIdx+1] = color[1]; 323 | rgbdata[iLedIdx+2] = color[2]; 324 | } 325 | 326 | return rgbdata; 327 | } 328 | 329 | function sendColors(overrideColor) 330 | { 331 | const rgbdata = grabColors(overrideColor); 332 | 333 | const LedsPerPacket = 9; 334 | let BytesSent = 0; 335 | let BytesLeft = rgbdata.length; 336 | 337 | while(BytesLeft > 0) 338 | { 339 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 340 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 341 | 342 | BytesLeft -= BytesToSend; 343 | BytesSent += BytesToSend; 344 | } 345 | } 346 | 347 | function StreamLightingData(StartLedIdx, RGBData) 348 | { 349 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 350 | device.write(packet, 33); 351 | } 352 | 353 | function hexToRgb(hex) 354 | { 355 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 356 | const colors = []; 357 | colors[0] = parseInt(result[1], 16); 358 | colors[1] = parseInt(result[2], 16); 359 | colors[2] = parseInt(result[3], 16); 360 | 361 | return colors; 362 | } 363 | 364 | export function Validate(endpoint) 365 | { 366 | return endpoint.interface === 1; 367 | } -------------------------------------------------------------------------------- /Keychron/Q Series/Max/Keychron_Q8_Max_QMK_ANSI_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "Keychron Q8 Max ANSI QMK Keyboard"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x3434; } 4 | export function ProductId() { return 0x0880; } 5 | export function Publisher() { return "SAMMY"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard";} 8 | export function Size() { return [15, 5]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() { 18 | return [ 19 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 20 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#000000"}, 21 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 22 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 23 | ]; 24 | } 25 | 26 | //Plugin Version: Built for Protocol V1.0.6 27 | 28 | const vKeys = [ 29 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, //14 30 | 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, //15 31 | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, //14 32 | 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, //14 33 | 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67 //11 34 | ]; 35 | 36 | const vKeyNames = [ 37 | "Esc", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", //14 38 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", "Del", //15 39 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter", "Ins", //14 40 | "Left Shift", "Z", "X", "C", "V", "B", "Menu", "N", "M", ",", ".", "/", "Right Shift", "Up Arrow", //14 41 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Win", "Fn", "ContextMenu", "Right Alt", "Left Arrow", "Down Arrow", "Right Arrow", //11 42 | ]; 43 | 44 | const vKeyPositions = [ 45 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], //14 46 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], [14, 1], //15 47 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [13, 2], [14, 2], //14 48 | [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [11, 3], [12, 3], [14, 3], //14 49 | [0, 4], [1, 4], [2, 4], [5, 4], [6, 4], [7, 4], [8, 4], [10, 4], [12, 4], [13, 4], [14, 4] //11 50 | ]; 51 | 52 | let LEDCount = 0; 53 | let IsViaKeyboard = false; 54 | const MainlineQMKFirmware = 1; 55 | const VIAFirmware = 2; 56 | const PluginProtocolVersion = "1.0.6"; 57 | 58 | export function LedNames() { 59 | return vKeyNames; 60 | } 61 | 62 | export function LedPositions() { 63 | return vKeyPositions; 64 | } 65 | 66 | export function vKeysArrayCount() { 67 | device.log('vKeys ' + vKeys.length); 68 | device.log('vKeyNames ' + vKeyNames.length); 69 | device.log('vKeyPositions ' + vKeyPositions.length); 70 | } 71 | 72 | export function Initialize() { 73 | requestFirmwareType(); 74 | requestQMKVersion(); 75 | requestSignalRGBProtocolVersion(); 76 | requestUniqueIdentifier(); 77 | requestTotalLeds(); 78 | effectEnable(); 79 | 80 | } 81 | 82 | export function Render() { 83 | sendColors(); 84 | } 85 | 86 | export function Shutdown(SystemSuspending) { 87 | 88 | if(SystemSuspending) { 89 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 90 | } else { 91 | if (shutdownMode === "SignalRGB") { 92 | sendColors(shutdownColor); 93 | } else { 94 | effectDisable(); 95 | } 96 | } 97 | 98 | //vKeysArrayCount(); // For debugging array counts 99 | 100 | } 101 | 102 | function commandHandler() { 103 | const readCounts = []; 104 | 105 | do { 106 | const returnpacket = device.read([0x00], 32, 10); 107 | processCommands(returnpacket); 108 | 109 | readCounts.push(device.getLastReadSize()); 110 | 111 | // Extra Read to throw away empty packets from Via 112 | // Via always sends a second packet with the same Command Id. 113 | if(IsViaKeyboard) { 114 | device.read([0x00], 32, 10); 115 | } 116 | } 117 | while(device.getLastReadSize() > 0); 118 | 119 | } 120 | 121 | function processCommands(data) { 122 | switch(data[1]) { 123 | case 0x21: 124 | returnQMKVersion(data); 125 | break; 126 | case 0x22: 127 | returnSignalRGBProtocolVersion(data); 128 | break; 129 | case 0x23: 130 | returnUniqueIdentifier(data); 131 | break; 132 | case 0x24: 133 | sendColors(); 134 | break; 135 | case 0x27: 136 | returnTotalLeds(data); 137 | break; 138 | case 0x28: 139 | returnFirmwareType(data); 140 | break; 141 | } 142 | } 143 | 144 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 145 | { 146 | device.write([0x00, 0x21], 32); 147 | device.pause(30); 148 | commandHandler(); 149 | } 150 | 151 | function returnQMKVersion(data) { 152 | const QMKVersionByte1 = data[2]; 153 | const QMKVersionByte2 = data[3]; 154 | const QMKVersionByte3 = data[4]; 155 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 156 | device.log("QMK SRGB Plugin Version: "+ Version()); 157 | device.pause(30); 158 | } 159 | 160 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 161 | { 162 | device.write([0x00, 0x22], 32); 163 | device.pause(30); 164 | commandHandler(); 165 | } 166 | 167 | function returnSignalRGBProtocolVersion(data) { 168 | const ProtocolVersionByte1 = data[2]; 169 | const ProtocolVersionByte2 = data[3]; 170 | const ProtocolVersionByte3 = data[4]; 171 | 172 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 173 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 174 | 175 | 176 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) { 177 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 178 | } 179 | 180 | device.pause(30); 181 | } 182 | 183 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 184 | { 185 | if(device.write([0x00, 0x23], 32) === -1) { 186 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 187 | } 188 | 189 | device.pause(30); 190 | commandHandler(); 191 | } 192 | 193 | 194 | function returnUniqueIdentifier(data) { 195 | const UniqueIdentifierByte1 = data[2]; 196 | const UniqueIdentifierByte2 = data[3]; 197 | const UniqueIdentifierByte3 = data[4]; 198 | 199 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) { 200 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 201 | } 202 | 203 | device.pause(30); 204 | } 205 | 206 | function requestTotalLeds() //Calculate total number of LEDs 207 | { 208 | device.write([0x00, 0x27], 32); 209 | device.pause(30); 210 | commandHandler(); 211 | } 212 | 213 | function returnTotalLeds(data) { 214 | LEDCount = data[2]; 215 | device.log("Device Total LED Count: " + LEDCount); 216 | device.pause(30); 217 | } 218 | 219 | function requestFirmwareType() { 220 | device.write([0x00, 0x28], 32); 221 | device.pause(30); 222 | commandHandler(); 223 | } 224 | 225 | function returnFirmwareType(data) { 226 | const FirmwareTypeByte = data[2]; 227 | 228 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) { 229 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 230 | } 231 | 232 | if(FirmwareTypeByte === MainlineQMKFirmware) { 233 | IsViaKeyboard = false; 234 | device.log("Firmware Type: Mainline"); 235 | } 236 | 237 | if(FirmwareTypeByte === VIAFirmware) { 238 | IsViaKeyboard = true; 239 | device.log("Firmware Type: VIA"); 240 | } 241 | 242 | device.pause(30); 243 | } 244 | 245 | function effectEnable() //Enable the SignalRGB Effect Mode 246 | { 247 | device.write([0x00, 0x25], 32); 248 | device.pause(30); 249 | } 250 | 251 | function effectDisable() //Revert to Hardware Mode 252 | { 253 | device.write([0x00, 0x26], 32); 254 | device.pause(30); 255 | } 256 | 257 | function createSolidColorArray(color) { 258 | const rgbdata = new Array(vKeys.length * 3).fill(0); 259 | 260 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 261 | const iLedIdx = vKeys[iIdx] * 3; 262 | rgbdata[iLedIdx] = color[0]; 263 | rgbdata[iLedIdx+1] = color[1]; 264 | rgbdata[iLedIdx+2] = color[2]; 265 | } 266 | 267 | return rgbdata; 268 | } 269 | 270 | function grabColors(overrideColor) { 271 | if(overrideColor) { 272 | return createSolidColorArray(hexToRgb(overrideColor)); 273 | } else if (LightingMode === "Forced") { 274 | return createSolidColorArray(hexToRgb(forcedColor)); 275 | } 276 | 277 | const rgbdata = new Array(vKeys.length * 3).fill(0); 278 | 279 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 280 | const iPxX = vKeyPositions[iIdx][0]; 281 | const iPxY = vKeyPositions[iIdx][1]; 282 | const color = device.color(iPxX, iPxY); 283 | 284 | const iLedIdx = vKeys[iIdx] * 3; 285 | rgbdata[iLedIdx] = color[0]; 286 | rgbdata[iLedIdx+1] = color[1]; 287 | rgbdata[iLedIdx+2] = color[2]; 288 | } 289 | 290 | return rgbdata; 291 | } 292 | 293 | function sendColors(overrideColor) { 294 | const rgbdata = grabColors(overrideColor); 295 | 296 | const LedsPerPacket = 9; 297 | let BytesSent = 0; 298 | let BytesLeft = rgbdata.length; 299 | 300 | while(BytesLeft > 0) { 301 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 302 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 303 | 304 | BytesLeft -= BytesToSend; 305 | BytesSent += BytesToSend; 306 | } 307 | } 308 | 309 | function StreamLightingData(StartLedIdx, RGBData) { 310 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 311 | device.write(packet, 33); 312 | } 313 | 314 | function hexToRgb(hex) { 315 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 316 | const colors = []; 317 | colors[0] = parseInt(result[1], 16); 318 | colors[1] = parseInt(result[2], 16); 319 | colors[2] = parseInt(result[3], 16); 320 | 321 | return colors; 322 | } 323 | 324 | export function Validate(endpoint) { 325 | return endpoint.interface === 1; 326 | } 327 | 328 | export function Image() { 329 | return ""; 330 | } -------------------------------------------------------------------------------- /Keychron/Q Series/Pro/Keychron_Q8_Pro_QMK_ANSI_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "Keychron Q8 Pro ANSI QMK Keyboard"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x3434; } 4 | export function ProductId() { return 0x0680; } 5 | export function Publisher() { return "WhirlwindFX"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [15, 5]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() { 18 | return [ 19 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 20 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#000000"}, 21 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 22 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 23 | ]; 24 | } 25 | 26 | //Plugin Version: Built for Protocol V1.0.6 27 | 28 | const vKeys = [ 29 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, //14 30 | 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, //15 31 | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, //14 32 | 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, //14 33 | 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67 //11 34 | ]; 35 | 36 | const vKeyNames = [ 37 | "Esc", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", //14 38 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", "Del", //15 39 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter", "Ins", //14 40 | "Left Shift", "Z", "X", "C", "V", "B", "Menu", "N", "M", ",", ".", "/", "Right Shift", "Up Arrow", //14 41 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Win", "Fn", "ContextMenu", "Right Alt", "Left Arrow", "Down Arrow", "Right Arrow", //11 42 | ]; 43 | 44 | const vKeyPositions = [ 45 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], //14 46 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], [14, 1], //15 47 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [13, 2], [14, 2], //14 48 | [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [11, 3], [12, 3], [14, 3], //14 49 | [0, 4], [1, 4], [2, 4], [5, 4], [6, 4], [7, 4], [8, 4], [10, 4], [12, 4], [13, 4], [14, 4] //11 50 | ]; 51 | 52 | let LEDCount = 0; 53 | let IsViaKeyboard = false; 54 | const MainlineQMKFirmware = 1; 55 | const VIAFirmware = 2; 56 | const PluginProtocolVersion = "1.0.6"; 57 | 58 | export function LedNames() { 59 | return vKeyNames; 60 | } 61 | 62 | export function LedPositions() { 63 | return vKeyPositions; 64 | } 65 | 66 | export function vKeysArrayCount() { 67 | device.log('vKeys ' + vKeys.length); 68 | device.log('vKeyNames ' + vKeyNames.length); 69 | device.log('vKeyPositions ' + vKeyPositions.length); 70 | } 71 | 72 | export function Initialize() { 73 | requestFirmwareType(); 74 | requestQMKVersion(); 75 | requestSignalRGBProtocolVersion(); 76 | requestUniqueIdentifier(); 77 | requestTotalLeds(); 78 | effectEnable(); 79 | 80 | } 81 | 82 | export function Render() { 83 | sendColors(); 84 | } 85 | 86 | export function Shutdown(SystemSuspending) { 87 | 88 | if(SystemSuspending) { 89 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 90 | } else { 91 | if (shutdownMode === "SignalRGB") { 92 | sendColors(shutdownColor); 93 | } else { 94 | effectDisable(); 95 | } 96 | } 97 | 98 | //vKeysArrayCount(); // For debugging array counts 99 | 100 | } 101 | 102 | function commandHandler() { 103 | const readCounts = []; 104 | 105 | do { 106 | const returnpacket = device.read([0x00], 32, 10); 107 | processCommands(returnpacket); 108 | 109 | readCounts.push(device.getLastReadSize()); 110 | 111 | // Extra Read to throw away empty packets from Via 112 | // Via always sends a second packet with the same Command Id. 113 | if(IsViaKeyboard) { 114 | device.read([0x00], 32, 10); 115 | } 116 | } 117 | while(device.getLastReadSize() > 0); 118 | 119 | } 120 | 121 | function processCommands(data) { 122 | switch(data[1]) { 123 | case 0x21: 124 | returnQMKVersion(data); 125 | break; 126 | case 0x22: 127 | returnSignalRGBProtocolVersion(data); 128 | break; 129 | case 0x23: 130 | returnUniqueIdentifier(data); 131 | break; 132 | case 0x24: 133 | sendColors(); 134 | break; 135 | case 0x27: 136 | returnTotalLeds(data); 137 | break; 138 | case 0x28: 139 | returnFirmwareType(data); 140 | break; 141 | } 142 | } 143 | 144 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 145 | { 146 | device.write([0x00, 0x21], 32); 147 | device.pause(30); 148 | commandHandler(); 149 | } 150 | 151 | function returnQMKVersion(data) { 152 | const QMKVersionByte1 = data[2]; 153 | const QMKVersionByte2 = data[3]; 154 | const QMKVersionByte3 = data[4]; 155 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 156 | device.log("QMK SRGB Plugin Version: "+ Version()); 157 | device.pause(30); 158 | } 159 | 160 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 161 | { 162 | device.write([0x00, 0x22], 32); 163 | device.pause(30); 164 | commandHandler(); 165 | } 166 | 167 | function returnSignalRGBProtocolVersion(data) { 168 | const ProtocolVersionByte1 = data[2]; 169 | const ProtocolVersionByte2 = data[3]; 170 | const ProtocolVersionByte3 = data[4]; 171 | 172 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 173 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 174 | 175 | 176 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) { 177 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 178 | } 179 | 180 | device.pause(30); 181 | } 182 | 183 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 184 | { 185 | if(device.write([0x00, 0x23], 32) === -1) { 186 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 187 | } 188 | 189 | device.pause(30); 190 | commandHandler(); 191 | } 192 | 193 | 194 | function returnUniqueIdentifier(data) { 195 | const UniqueIdentifierByte1 = data[2]; 196 | const UniqueIdentifierByte2 = data[3]; 197 | const UniqueIdentifierByte3 = data[4]; 198 | 199 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) { 200 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 201 | } 202 | 203 | device.pause(30); 204 | } 205 | 206 | function requestTotalLeds() //Calculate total number of LEDs 207 | { 208 | device.write([0x00, 0x27], 32); 209 | device.pause(30); 210 | commandHandler(); 211 | } 212 | 213 | function returnTotalLeds(data) { 214 | LEDCount = data[2]; 215 | device.log("Device Total LED Count: " + LEDCount); 216 | device.pause(30); 217 | } 218 | 219 | function requestFirmwareType() { 220 | device.write([0x00, 0x28], 32); 221 | device.pause(30); 222 | commandHandler(); 223 | } 224 | 225 | function returnFirmwareType(data) { 226 | const FirmwareTypeByte = data[2]; 227 | 228 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) { 229 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 230 | } 231 | 232 | if(FirmwareTypeByte === MainlineQMKFirmware) { 233 | IsViaKeyboard = false; 234 | device.log("Firmware Type: Mainline"); 235 | } 236 | 237 | if(FirmwareTypeByte === VIAFirmware) { 238 | IsViaKeyboard = true; 239 | device.log("Firmware Type: VIA"); 240 | } 241 | 242 | device.pause(30); 243 | } 244 | 245 | function effectEnable() //Enable the SignalRGB Effect Mode 246 | { 247 | device.write([0x00, 0x25], 32); 248 | device.pause(30); 249 | } 250 | 251 | function effectDisable() //Revert to Hardware Mode 252 | { 253 | device.write([0x00, 0x26], 32); 254 | device.pause(30); 255 | } 256 | 257 | function createSolidColorArray(color) { 258 | const rgbdata = new Array(vKeys.length * 3).fill(0); 259 | 260 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 261 | const iLedIdx = vKeys[iIdx] * 3; 262 | rgbdata[iLedIdx] = color[0]; 263 | rgbdata[iLedIdx+1] = color[1]; 264 | rgbdata[iLedIdx+2] = color[2]; 265 | } 266 | 267 | return rgbdata; 268 | } 269 | 270 | function grabColors(overrideColor) { 271 | if(overrideColor) { 272 | return createSolidColorArray(hexToRgb(overrideColor)); 273 | } else if (LightingMode === "Forced") { 274 | return createSolidColorArray(hexToRgb(forcedColor)); 275 | } 276 | 277 | const rgbdata = new Array(vKeys.length * 3).fill(0); 278 | 279 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 280 | const iPxX = vKeyPositions[iIdx][0]; 281 | const iPxY = vKeyPositions[iIdx][1]; 282 | const color = device.color(iPxX, iPxY); 283 | 284 | const iLedIdx = vKeys[iIdx] * 3; 285 | rgbdata[iLedIdx] = color[0]; 286 | rgbdata[iLedIdx+1] = color[1]; 287 | rgbdata[iLedIdx+2] = color[2]; 288 | } 289 | 290 | return rgbdata; 291 | } 292 | 293 | function sendColors(overrideColor) { 294 | const rgbdata = grabColors(overrideColor); 295 | 296 | const LedsPerPacket = 9; 297 | let BytesSent = 0; 298 | let BytesLeft = rgbdata.length; 299 | 300 | while(BytesLeft > 0) { 301 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 302 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 303 | 304 | BytesLeft -= BytesToSend; 305 | BytesSent += BytesToSend; 306 | } 307 | } 308 | 309 | function StreamLightingData(StartLedIdx, RGBData) { 310 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 311 | device.write(packet, 33); 312 | } 313 | 314 | function hexToRgb(hex) { 315 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 316 | const colors = []; 317 | colors[0] = parseInt(result[1], 16); 318 | colors[1] = parseInt(result[2], 16); 319 | colors[2] = parseInt(result[3], 16); 320 | 321 | return colors; 322 | } 323 | 324 | export function Validate(endpoint) { 325 | return endpoint.interface === 1; 326 | } 327 | 328 | export function Image() { 329 | return ""; 330 | } -------------------------------------------------------------------------------- /KBDFans/KBDFans_KBD67_V2_QMK_ISO_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "KBDfans KBD67MKIIRGB ISO QMK Keyboard"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x4b42; } 4 | export function ProductId() { return 0x0105; } 5 | export function Publisher() { return "mestermandarin"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [15, 5]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() 18 | { 19 | return [ 20 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 21 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"000000"}, 22 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 23 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"009bde"}, 24 | ]; 25 | } 26 | 27 | //Plugin Version: Built for Protocol V1.0.6 28 | 29 | const vKeys = [ 30 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 31 | 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 32 | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 33 | 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 34 | 59, 60, 61, 62, 63, 64, 65, 66, 67 35 | ]; 36 | 37 | const vKeyNames = [ 38 | "Esc", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", "Home", 39 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "Page Up", 40 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "\\", "Enter", "Page Down", 41 | "Left Shift", "ISO", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Right Shift", "Up Arrow", "End", 42 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Alt", "Menu", "Left Arrow", "Down Arrow", "Right Arrow" 43 | ]; 44 | 45 | const vKeyPositions = [ 46 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], [14, 0], 47 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [14, 1], 48 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [12, 2], [13, 2], [14, 2], 49 | [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [11, 3], [12, 3], [13, 3], [14, 3], 50 | [0, 4], [1, 4], [2, 4], [6, 4], [10, 4], [11, 4], [12, 4], [13, 4], [14, 4] 51 | ]; 52 | 53 | let LEDCount = 0; 54 | let IsViaKeyboard = false; 55 | const MainlineQMKFirmware = 1; 56 | const VIAFirmware = 2; 57 | const PluginProtocolVersion = "1.0.6"; 58 | 59 | export function LedNames() 60 | { 61 | return vKeyNames; 62 | } 63 | 64 | export function LedPositions() 65 | { 66 | return vKeyPositions; 67 | } 68 | 69 | export function vKeysArrayCount() 70 | { 71 | device.log('vKeys ' + vKeys.length); 72 | device.log('vKeyNames ' + vKeyNames.length); 73 | device.log('vKeyPositions ' + vKeyPositions.length); 74 | } 75 | 76 | export function Initialize() 77 | { 78 | requestFirmwareType(); 79 | requestQMKVersion(); 80 | requestSignalRGBProtocolVersion(); 81 | requestUniqueIdentifier(); 82 | requestTotalLeds(); 83 | effectEnable(); 84 | 85 | } 86 | 87 | export function Render() 88 | { 89 | sendColors(); 90 | } 91 | 92 | export function Shutdown(SystemSuspending) 93 | { 94 | 95 | if(SystemSuspending) 96 | { 97 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 98 | } 99 | else 100 | { 101 | if (shutdownMode === "SignalRGB") 102 | { 103 | sendColors(shutdownColor); 104 | } 105 | else 106 | { 107 | effectDisable(); 108 | } 109 | } 110 | //vKeysArrayCount(); // For debugging array counts 111 | 112 | } 113 | 114 | function commandHandler() 115 | { 116 | const readCounts = []; 117 | 118 | do 119 | { 120 | const returnpacket = device.read([0x00], 32, 10); 121 | processCommands(returnpacket); 122 | 123 | readCounts.push(device.getLastReadSize()); 124 | 125 | // Extra Read to throw away empty packets from Via 126 | // Via always sends a second packet with the same Command Id. 127 | if(IsViaKeyboard) 128 | { 129 | device.read([0x00], 32, 10); 130 | } 131 | } 132 | while(device.getLastReadSize() > 0); 133 | 134 | } 135 | 136 | function processCommands(data) 137 | { 138 | switch(data[1]) 139 | { 140 | case 0x21: 141 | returnQMKVersion(data); 142 | break; 143 | case 0x22: 144 | returnSignalRGBProtocolVersion(data); 145 | break; 146 | case 0x23: 147 | returnUniqueIdentifier(data); 148 | break; 149 | case 0x24: 150 | sendColors(); 151 | break; 152 | case 0x27: 153 | returnTotalLeds(data); 154 | break; 155 | case 0x28: 156 | returnFirmwareType(data); 157 | break; 158 | } 159 | } 160 | 161 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 162 | { 163 | device.write([0x00, 0x21], 32); 164 | device.pause(30); 165 | commandHandler(); 166 | } 167 | 168 | function returnQMKVersion(data) 169 | { 170 | const QMKVersionByte1 = data[2]; 171 | const QMKVersionByte2 = data[3]; 172 | const QMKVersionByte3 = data[4]; 173 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 174 | device.log("QMK SRGB Plugin Version: "+ Version()); 175 | device.pause(30); 176 | } 177 | 178 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 179 | { 180 | device.write([0x00, 0x22], 32); 181 | device.pause(30); 182 | commandHandler(); 183 | } 184 | 185 | function returnSignalRGBProtocolVersion(data) 186 | { 187 | const ProtocolVersionByte1 = data[2]; 188 | const ProtocolVersionByte2 = data[3]; 189 | const ProtocolVersionByte3 = data[4]; 190 | 191 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 192 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 193 | 194 | 195 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) 196 | { 197 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 198 | } 199 | 200 | device.pause(30); 201 | } 202 | 203 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 204 | { 205 | if(device.write([0x00, 0x23], 32) === -1) 206 | { 207 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 208 | } 209 | 210 | device.pause(30); 211 | commandHandler(); 212 | } 213 | 214 | 215 | function returnUniqueIdentifier(data) 216 | { 217 | const UniqueIdentifierByte1 = data[2]; 218 | const UniqueIdentifierByte2 = data[3]; 219 | const UniqueIdentifierByte3 = data[4]; 220 | 221 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) 222 | { 223 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 224 | } 225 | 226 | device.pause(30); 227 | } 228 | 229 | function requestTotalLeds() //Calculate total number of LEDs 230 | { 231 | device.write([0x00, 0x27], 32); 232 | device.pause(30); 233 | commandHandler(); 234 | } 235 | 236 | function returnTotalLeds(data) 237 | { 238 | LEDCount = data[2]; 239 | device.log("Device Total LED Count: " + LEDCount); 240 | device.pause(30); 241 | } 242 | 243 | function requestFirmwareType() 244 | { 245 | device.write([0x00, 0x28], 32); 246 | device.pause(30); 247 | commandHandler(); 248 | } 249 | 250 | function returnFirmwareType(data) 251 | { 252 | const FirmwareTypeByte = data[2]; 253 | 254 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) 255 | { 256 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 257 | } 258 | 259 | if(FirmwareTypeByte === MainlineQMKFirmware) 260 | { 261 | IsViaKeyboard = false; 262 | device.log("Firmware Type: Mainline"); 263 | } 264 | 265 | if(FirmwareTypeByte === VIAFirmware) 266 | { 267 | IsViaKeyboard = true; 268 | device.log("Firmware Type: VIA"); 269 | } 270 | 271 | device.pause(30); 272 | } 273 | 274 | function effectEnable() //Enable the SignalRGB Effect Mode 275 | { 276 | device.write([0x00, 0x25], 32); 277 | device.pause(30); 278 | } 279 | 280 | function effectDisable() //Revert to Hardware Mode 281 | { 282 | device.write([0x00, 0x26], 32); 283 | device.pause(30); 284 | } 285 | 286 | function createSolidColorArray(color) 287 | { 288 | const rgbdata = new Array(vKeys.length * 3).fill(0); 289 | 290 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 291 | { 292 | const iLedIdx = vKeys[iIdx] * 3; 293 | rgbdata[iLedIdx] = color[0]; 294 | rgbdata[iLedIdx+1] = color[1]; 295 | rgbdata[iLedIdx+2] = color[2]; 296 | } 297 | 298 | return rgbdata; 299 | } 300 | 301 | function grabColors(overrideColor) 302 | { 303 | if(overrideColor) 304 | { 305 | return createSolidColorArray(hexToRgb(overrideColor)); 306 | } 307 | else if (LightingMode === "Forced") 308 | { 309 | return createSolidColorArray(hexToRgb(forcedColor)); 310 | } 311 | 312 | const rgbdata = new Array(vKeys.length * 3).fill(0); 313 | 314 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 315 | { 316 | const iPxX = vKeyPositions[iIdx][0]; 317 | const iPxY = vKeyPositions[iIdx][1]; 318 | let color = device.color(iPxX, iPxY); 319 | 320 | const iLedIdx = vKeys[iIdx] * 3; 321 | rgbdata[iLedIdx] = color[0]; 322 | rgbdata[iLedIdx+1] = color[1]; 323 | rgbdata[iLedIdx+2] = color[2]; 324 | } 325 | 326 | return rgbdata; 327 | } 328 | 329 | function sendColors(overrideColor) 330 | { 331 | const rgbdata = grabColors(overrideColor); 332 | 333 | const LedsPerPacket = 9; 334 | let BytesSent = 0; 335 | let BytesLeft = rgbdata.length; 336 | 337 | while(BytesLeft > 0) 338 | { 339 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 340 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 341 | 342 | BytesLeft -= BytesToSend; 343 | BytesSent += BytesToSend; 344 | } 345 | } 346 | 347 | function StreamLightingData(StartLedIdx, RGBData) 348 | { 349 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 350 | device.write(packet, 33); 351 | } 352 | 353 | function hexToRgb(hex) 354 | { 355 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 356 | const colors = []; 357 | colors[0] = parseInt(result[1], 16); 358 | colors[1] = parseInt(result[2], 16); 359 | colors[2] = parseInt(result[3], 16); 360 | 361 | return colors; 362 | } 363 | 364 | export function Validate(endpoint) 365 | { 366 | return endpoint.interface === 1; 367 | } -------------------------------------------------------------------------------- /Keychron/Q Series/Standard/Keychron_Q0_QMK_ANSI_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "Keychron Q0 QMK Keyboard"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x3434; } 4 | export function ProductId() { return 0x0130; } 5 | export function Publisher() { return "Caedendi & WhirlwindFX"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [4, 6]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() 18 | { 19 | return [ 20 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 21 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"000000"}, 22 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 23 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"009bde"}, 24 | ]; 25 | } 26 | 27 | //Plugin Version: Built for Protocol V1.0.6 28 | 29 | const vKeys = 30 | [ 31 | 0, 1, 2, 3, 32 | 4, 5, 6, 7, 33 | 8, 9, 10, 34 | 11, 12, 13, 14, 35 | 15, 16, 17, 36 | 18, 19, 20 37 | ]; 38 | const vKeyNames = 39 | [ 40 | "Circle", "Triangle", "Square", "Cross", 41 | "NumLock", "Num /", "Num *", "Num -", 42 | "Num 7", "Num 8", "Num 9", 43 | "Num 4", "Num 5", "Num 6", "Num +", 44 | "Num 1", "Num 2", "Num 3", 45 | "Num 0", "Num .", "Num Enter" 46 | ]; 47 | 48 | const vKeyPositions = 49 | [ 50 | [0, 0], [1, 0], [2, 0], [3, 0], 51 | [0, 1], [1, 1], [2, 1], [3, 1], 52 | [0, 2], [1, 2], [2, 2], 53 | [0, 3], [1, 3], [2, 3], [3, 3], 54 | [0, 4], [1, 4], [2, 4], 55 | [0, 5], [2, 5], [3, 5] 56 | ]; 57 | 58 | let LEDCount = 0; 59 | let IsViaKeyboard = false; 60 | const MainlineQMKFirmware = 1; 61 | const VIAFirmware = 2; 62 | const PluginProtocolVersion = "1.0.6"; 63 | 64 | export function LedNames() 65 | { 66 | return vKeyNames; 67 | } 68 | 69 | export function LedPositions() 70 | { 71 | return vKeyPositions; 72 | } 73 | 74 | export function vKeysArrayCount() 75 | { 76 | device.log('vKeys ' + vKeys.length); 77 | device.log('vKeyNames ' + vKeyNames.length); 78 | device.log('vKeyPositions ' + vKeyPositions.length); 79 | } 80 | 81 | export function Initialize() 82 | { 83 | requestFirmwareType(); 84 | requestQMKVersion(); 85 | requestSignalRGBProtocolVersion(); 86 | requestUniqueIdentifier(); 87 | requestTotalLeds(); 88 | effectEnable(); 89 | 90 | } 91 | 92 | export function Render() 93 | { 94 | sendColors(); 95 | } 96 | 97 | export function Shutdown(SystemSuspending) 98 | { 99 | 100 | if(SystemSuspending) 101 | { 102 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 103 | } 104 | else 105 | { 106 | if (shutdownMode === "SignalRGB") 107 | { 108 | sendColors(shutdownColor); 109 | } 110 | else 111 | { 112 | effectDisable(); 113 | } 114 | } 115 | //vKeysArrayCount(); // For debugging array counts 116 | 117 | } 118 | 119 | function commandHandler() 120 | { 121 | const readCounts = []; 122 | 123 | do 124 | { 125 | const returnpacket = device.read([0x00], 32, 10); 126 | processCommands(returnpacket); 127 | 128 | readCounts.push(device.getLastReadSize()); 129 | 130 | // Extra Read to throw away empty packets from Via 131 | // Via always sends a second packet with the same Command Id. 132 | if(IsViaKeyboard) 133 | { 134 | device.read([0x00], 32, 10); 135 | } 136 | } 137 | while(device.getLastReadSize() > 0); 138 | 139 | } 140 | 141 | function processCommands(data) 142 | { 143 | switch(data[1]) 144 | { 145 | case 0x21: 146 | returnQMKVersion(data); 147 | break; 148 | case 0x22: 149 | returnSignalRGBProtocolVersion(data); 150 | break; 151 | case 0x23: 152 | returnUniqueIdentifier(data); 153 | break; 154 | case 0x24: 155 | sendColors(); 156 | break; 157 | case 0x27: 158 | returnTotalLeds(data); 159 | break; 160 | case 0x28: 161 | returnFirmwareType(data); 162 | break; 163 | } 164 | } 165 | 166 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 167 | { 168 | device.write([0x00, 0x21], 32); 169 | device.pause(30); 170 | commandHandler(); 171 | } 172 | 173 | function returnQMKVersion(data) 174 | { 175 | const QMKVersionByte1 = data[2]; 176 | const QMKVersionByte2 = data[3]; 177 | const QMKVersionByte3 = data[4]; 178 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 179 | device.log("QMK SRGB Plugin Version: "+ Version()); 180 | device.pause(30); 181 | } 182 | 183 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 184 | { 185 | device.write([0x00, 0x22], 32); 186 | device.pause(30); 187 | commandHandler(); 188 | } 189 | 190 | function returnSignalRGBProtocolVersion(data) 191 | { 192 | const ProtocolVersionByte1 = data[2]; 193 | const ProtocolVersionByte2 = data[3]; 194 | const ProtocolVersionByte3 = data[4]; 195 | 196 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 197 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 198 | 199 | 200 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) 201 | { 202 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 203 | } 204 | 205 | device.pause(30); 206 | } 207 | 208 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 209 | { 210 | if(device.write([0x00, 0x23], 32) === -1) 211 | { 212 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 213 | } 214 | 215 | device.pause(30); 216 | commandHandler(); 217 | } 218 | 219 | 220 | function returnUniqueIdentifier(data) 221 | { 222 | const UniqueIdentifierByte1 = data[2]; 223 | const UniqueIdentifierByte2 = data[3]; 224 | const UniqueIdentifierByte3 = data[4]; 225 | 226 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) 227 | { 228 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 229 | } 230 | 231 | device.pause(30); 232 | } 233 | 234 | function requestTotalLeds() //Calculate total number of LEDs 235 | { 236 | device.write([0x00, 0x27], 32); 237 | device.pause(30); 238 | commandHandler(); 239 | } 240 | 241 | function returnTotalLeds(data) 242 | { 243 | LEDCount = data[2]; 244 | device.log("Device Total LED Count: " + LEDCount); 245 | device.pause(30); 246 | } 247 | 248 | function requestFirmwareType() 249 | { 250 | device.write([0x00, 0x28], 32); 251 | device.pause(30); 252 | commandHandler(); 253 | } 254 | 255 | function returnFirmwareType(data) 256 | { 257 | const FirmwareTypeByte = data[2]; 258 | 259 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) 260 | { 261 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 262 | } 263 | 264 | if(FirmwareTypeByte === MainlineQMKFirmware) 265 | { 266 | IsViaKeyboard = false; 267 | device.log("Firmware Type: Mainline"); 268 | } 269 | 270 | if(FirmwareTypeByte === VIAFirmware) 271 | { 272 | IsViaKeyboard = true; 273 | device.log("Firmware Type: VIA"); 274 | } 275 | 276 | device.pause(30); 277 | } 278 | 279 | function effectEnable() //Enable the SignalRGB Effect Mode 280 | { 281 | device.write([0x00, 0x25], 32); 282 | device.pause(30); 283 | } 284 | 285 | function effectDisable() //Revert to Hardware Mode 286 | { 287 | device.write([0x00, 0x26], 32); 288 | device.pause(30); 289 | } 290 | 291 | function createSolidColorArray(color) 292 | { 293 | const rgbdata = new Array(vKeys.length * 3).fill(0); 294 | 295 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 296 | { 297 | const iLedIdx = vKeys[iIdx] * 3; 298 | rgbdata[iLedIdx] = color[0]; 299 | rgbdata[iLedIdx+1] = color[1]; 300 | rgbdata[iLedIdx+2] = color[2]; 301 | } 302 | 303 | return rgbdata; 304 | } 305 | 306 | function grabColors(overrideColor) 307 | { 308 | if(overrideColor) 309 | { 310 | return createSolidColorArray(hexToRgb(overrideColor)); 311 | } 312 | else if (LightingMode === "Forced") 313 | { 314 | return createSolidColorArray(hexToRgb(forcedColor)); 315 | } 316 | 317 | const rgbdata = new Array(vKeys.length * 3).fill(0); 318 | 319 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 320 | { 321 | const iPxX = vKeyPositions[iIdx][0]; 322 | const iPxY = vKeyPositions[iIdx][1]; 323 | let color = device.color(iPxX, iPxY); 324 | 325 | const iLedIdx = vKeys[iIdx] * 3; 326 | rgbdata[iLedIdx] = color[0]; 327 | rgbdata[iLedIdx+1] = color[1]; 328 | rgbdata[iLedIdx+2] = color[2]; 329 | } 330 | 331 | return rgbdata; 332 | } 333 | 334 | function sendColors(overrideColor) 335 | { 336 | const rgbdata = grabColors(overrideColor); 337 | 338 | const LedsPerPacket = 9; 339 | let BytesSent = 0; 340 | let BytesLeft = rgbdata.length; 341 | 342 | while(BytesLeft > 0) 343 | { 344 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 345 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 346 | 347 | BytesLeft -= BytesToSend; 348 | BytesSent += BytesToSend; 349 | } 350 | } 351 | 352 | function StreamLightingData(StartLedIdx, RGBData) 353 | { 354 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 355 | device.write(packet, 33); 356 | } 357 | 358 | function hexToRgb(hex) 359 | { 360 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 361 | const colors = []; 362 | colors[0] = parseInt(result[1], 16); 363 | colors[1] = parseInt(result[2], 16); 364 | colors[2] = parseInt(result[3], 16); 365 | 366 | return colors; 367 | } 368 | 369 | export function Validate(endpoint) 370 | { 371 | return endpoint.interface === 1; 372 | } -------------------------------------------------------------------------------- /Keychron/K Series/Pro/Keychron_K6_Pro_ANSI_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "Keychron K6 Pro"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x3434; } 4 | export function ProductId() { return 0x0260; } 5 | export function Publisher() { return "Clayton011"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard";} 8 | export function Size() { return [16, 5]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() { 18 | return [ 19 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 20 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"#000000"}, 21 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 22 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"#009bde"}, 23 | ]; 24 | } 25 | 26 | //Plugin Version: Built for Protocol V1.0.6 27 | 28 | const vKeys = [ 29 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //15 30 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, //15 31 | 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, //14 32 | 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, //14 33 | 58, 59, 60, 61, 62, 63, 64, 65, 66, 67 //10 34 | ]; 35 | 36 | const vKeyNames = [ 37 | "Esc", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", "MediaStop", //15 38 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", "Home", //15 39 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter", "Page Up", //14 40 | "Left Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Right Shift", "Up Arrow", "Page Down", //14 41 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Alt", "Right Win", "Fn", "Left Arrow", "Down Arrow", "Right Arrow", //10 42 | ]; 43 | 44 | const vKeyPositions = [ 45 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], [14, 0], //15 46 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], [14, 1], //15 47 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [13, 2], [14, 2], //14 48 | [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [11, 3], [12, 3], [14, 3], //14 49 | [0, 4], [1, 4], [2, 4], [6, 4], [10, 4], [11, 4], [12, 4], [13, 4], [14, 4], [15, 4], //10 50 | ]; 51 | 52 | let LEDCount = 0; 53 | let IsViaKeyboard = false; 54 | const MainlineQMKFirmware = 1; 55 | const VIAFirmware = 2; 56 | const PluginProtocolVersion = "1.0.6"; 57 | 58 | export function LedNames() { 59 | return vKeyNames; 60 | } 61 | 62 | export function LedPositions() { 63 | return vKeyPositions; 64 | } 65 | 66 | export function vKeysArrayCount() { 67 | device.log('vKeys ' + vKeys.length); 68 | device.log('vKeyNames ' + vKeyNames.length); 69 | device.log('vKeyPositions ' + vKeyPositions.length); 70 | } 71 | 72 | export function Initialize() { 73 | requestFirmwareType(); 74 | requestQMKVersion(); 75 | requestSignalRGBProtocolVersion(); 76 | requestUniqueIdentifier(); 77 | requestTotalLeds(); 78 | effectEnable(); 79 | 80 | } 81 | 82 | export function Render() { 83 | sendColors(); 84 | } 85 | 86 | export function Shutdown(SystemSuspending) { 87 | 88 | if(SystemSuspending) { 89 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 90 | } else { 91 | if (shutdownMode === "SignalRGB") { 92 | sendColors(shutdownColor); 93 | } else { 94 | effectDisable(); 95 | } 96 | } 97 | 98 | //vKeysArrayCount(); // For debugging array counts 99 | 100 | } 101 | 102 | function commandHandler() { 103 | const readCounts = []; 104 | 105 | do { 106 | const returnpacket = device.read([0x00], 32, 10); 107 | processCommands(returnpacket); 108 | 109 | readCounts.push(device.getLastReadSize()); 110 | 111 | // Extra Read to throw away empty packets from Via 112 | // Via always sends a second packet with the same Command Id. 113 | if(IsViaKeyboard) { 114 | device.read([0x00], 32, 10); 115 | } 116 | } 117 | while(device.getLastReadSize() > 0); 118 | 119 | } 120 | 121 | function processCommands(data) { 122 | switch(data[1]) { 123 | case 0x21: 124 | returnQMKVersion(data); 125 | break; 126 | case 0x22: 127 | returnSignalRGBProtocolVersion(data); 128 | break; 129 | case 0x23: 130 | returnUniqueIdentifier(data); 131 | break; 132 | case 0x24: 133 | sendColors(); 134 | break; 135 | case 0x27: 136 | returnTotalLeds(data); 137 | break; 138 | case 0x28: 139 | returnFirmwareType(data); 140 | break; 141 | } 142 | } 143 | 144 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 145 | { 146 | device.write([0x00, 0x21], 32); 147 | device.pause(30); 148 | commandHandler(); 149 | } 150 | 151 | function returnQMKVersion(data) { 152 | const QMKVersionByte1 = data[2]; 153 | const QMKVersionByte2 = data[3]; 154 | const QMKVersionByte3 = data[4]; 155 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 156 | device.log("QMK SRGB Plugin Version: "+ Version()); 157 | device.pause(30); 158 | } 159 | 160 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 161 | { 162 | device.write([0x00, 0x22], 32); 163 | device.pause(30); 164 | commandHandler(); 165 | } 166 | 167 | function returnSignalRGBProtocolVersion(data) { 168 | const ProtocolVersionByte1 = data[2]; 169 | const ProtocolVersionByte2 = data[3]; 170 | const ProtocolVersionByte3 = data[4]; 171 | 172 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 173 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 174 | 175 | 176 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) { 177 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 178 | } 179 | 180 | device.pause(30); 181 | } 182 | 183 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 184 | { 185 | if(device.write([0x00, 0x23], 32) === -1) { 186 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 187 | } 188 | 189 | device.pause(30); 190 | commandHandler(); 191 | } 192 | 193 | 194 | function returnUniqueIdentifier(data) { 195 | const UniqueIdentifierByte1 = data[2]; 196 | const UniqueIdentifierByte2 = data[3]; 197 | const UniqueIdentifierByte3 = data[4]; 198 | 199 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) { 200 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 201 | } 202 | 203 | device.pause(30); 204 | } 205 | 206 | function requestTotalLeds() //Calculate total number of LEDs 207 | { 208 | device.write([0x00, 0x27], 32); 209 | device.pause(30); 210 | commandHandler(); 211 | } 212 | 213 | function returnTotalLeds(data) { 214 | LEDCount = data[2]; 215 | device.log("Device Total LED Count: " + LEDCount); 216 | device.pause(30); 217 | } 218 | 219 | function requestFirmwareType() { 220 | device.write([0x00, 0x28], 32); 221 | device.pause(30); 222 | commandHandler(); 223 | } 224 | 225 | function returnFirmwareType(data) { 226 | const FirmwareTypeByte = data[2]; 227 | 228 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) { 229 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 230 | } 231 | 232 | if(FirmwareTypeByte === MainlineQMKFirmware) { 233 | IsViaKeyboard = false; 234 | device.log("Firmware Type: Mainline"); 235 | } 236 | 237 | if(FirmwareTypeByte === VIAFirmware) { 238 | IsViaKeyboard = true; 239 | device.log("Firmware Type: VIA"); 240 | } 241 | 242 | device.pause(30); 243 | } 244 | 245 | function effectEnable() //Enable the SignalRGB Effect Mode 246 | { 247 | device.write([0x00, 0x25], 32); 248 | device.pause(30); 249 | } 250 | 251 | function effectDisable() //Revert to Hardware Mode 252 | { 253 | device.write([0x00, 0x26], 32); 254 | device.pause(30); 255 | } 256 | 257 | function createSolidColorArray(color) { 258 | const rgbdata = new Array(vKeys.length * 3).fill(0); 259 | 260 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 261 | const iLedIdx = vKeys[iIdx] * 3; 262 | rgbdata[iLedIdx] = color[0]; 263 | rgbdata[iLedIdx+1] = color[1]; 264 | rgbdata[iLedIdx+2] = color[2]; 265 | } 266 | 267 | return rgbdata; 268 | } 269 | 270 | function grabColors(overrideColor) { 271 | if(overrideColor) { 272 | return createSolidColorArray(hexToRgb(overrideColor)); 273 | } else if (LightingMode === "Forced") { 274 | return createSolidColorArray(hexToRgb(forcedColor)); 275 | } 276 | 277 | const rgbdata = new Array(vKeys.length * 3).fill(0); 278 | 279 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) { 280 | const iPxX = vKeyPositions[iIdx][0]; 281 | const iPxY = vKeyPositions[iIdx][1]; 282 | const color = device.color(iPxX, iPxY); 283 | 284 | const iLedIdx = vKeys[iIdx] * 3; 285 | rgbdata[iLedIdx] = color[0]; 286 | rgbdata[iLedIdx+1] = color[1]; 287 | rgbdata[iLedIdx+2] = color[2]; 288 | } 289 | 290 | return rgbdata; 291 | } 292 | 293 | function sendColors(overrideColor) { 294 | const rgbdata = grabColors(overrideColor); 295 | 296 | const LedsPerPacket = 9; 297 | let BytesSent = 0; 298 | let BytesLeft = rgbdata.length; 299 | 300 | while(BytesLeft > 0) { 301 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 302 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 303 | 304 | BytesLeft -= BytesToSend; 305 | BytesSent += BytesToSend; 306 | } 307 | } 308 | 309 | function StreamLightingData(StartLedIdx, RGBData) { 310 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 311 | device.write(packet, 33); 312 | } 313 | 314 | function hexToRgb(hex) { 315 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 316 | const colors = []; 317 | colors[0] = parseInt(result[1], 16); 318 | colors[1] = parseInt(result[2], 16); 319 | colors[2] = parseInt(result[3], 16); 320 | 321 | return colors; 322 | } 323 | 324 | export function Validate(endpoint) { 325 | return endpoint.interface === 1; 326 | } 327 | 328 | export function ImageUrl() { 329 | return "https://raw.githubusercontent.com/SRGBmods/QMK-Images/main/images/Keychron_K6_Pro_ANSI_Encoder.png"; 330 | } -------------------------------------------------------------------------------- /Keychron/V Series/Standard/Keychron_V2_QMK_ANSI_Keyboard.js: -------------------------------------------------------------------------------- 1 | export function Name() { return "Keychron V2 QMK Keyboard"; } 2 | export function Version() { return "1.1.9"; } 3 | export function VendorId() { return 0x3434; } 4 | export function ProductId() { return [0x0320, 0x0321]; } 5 | export function Publisher() { return "WhirlwindFX"; } 6 | export function Documentation() { return "qmk/srgbmods-qmk-firmware"; } 7 | export function DeviceType() { return "keyboard"; } 8 | export function Size() { return [15, 5]; } 9 | export function DefaultPosition(){return [10, 100]; } 10 | export function DefaultScale(){return 8.0;} 11 | /* global 12 | shutdownMode:readonly 13 | shutdownColor:readonly 14 | LightingMode:readonly 15 | forcedColor:readonly 16 | */ 17 | export function ControllableParameters() 18 | { 19 | return [ 20 | {"property":"shutdownMode", "group":"lighting", "label":"Shutdown Mode", "type":"combobox", "values":["SignalRGB", "Hardware"], "default":"SignalRGB"}, 21 | {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"000000"}, 22 | {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, 23 | {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"009bde"}, 24 | ]; 25 | } 26 | 27 | //Plugin Version: Built for Protocol V1.0.6 28 | 29 | const vKeys = [ 30 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, //14 31 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, //15 32 | 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, //14 33 | 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, //13 34 | 57, 58, 59, 60, 61, 62, 63, 64, 65, 66 //10 35 | ]; 36 | 37 | const vKeyNames = [ 38 | "Esc", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "Backspace", //14 39 | "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\", "Del", //15 40 | "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter", "Home", //14 41 | "Left Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Right Shift", "Up Arrow", //13 42 | "Left Ctrl", "Left Win", "Left Alt", "Space", "Right Alt", "FN1", "FN2", "Left Arrow", "Down Arrow", "Right Arrow" //10 43 | ]; 44 | 45 | const vKeyPositions = [ 46 | [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], //14 47 | [0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1], [10, 1], [11, 1], [12, 1], [13, 1], [14, 1], //15 48 | [0, 2], [1, 2], [2, 2], [3, 2], [4, 2], [5, 2], [6, 2], [7, 2], [8, 2], [9, 2], [10, 2], [11, 2], [13, 2], [14, 2], //14 49 | [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [5, 3], [6, 3], [7, 3], [8, 3], [9, 3], [10, 3], [11, 3], [13, 3], //13 50 | [0, 4], [1, 4], [2, 4], [5, 4], [9, 4], [10, 4], [11, 4], [12, 4], [13, 4], [14, 4] //10 51 | ]; 52 | 53 | let LEDCount = 0; 54 | let IsViaKeyboard = false; 55 | const MainlineQMKFirmware = 1; 56 | const VIAFirmware = 2; 57 | const PluginProtocolVersion = "1.0.6"; 58 | 59 | export function LedNames() 60 | { 61 | return vKeyNames; 62 | } 63 | 64 | export function LedPositions() 65 | { 66 | return vKeyPositions; 67 | } 68 | 69 | export function vKeysArrayCount() 70 | { 71 | device.log('vKeys ' + vKeys.length); 72 | device.log('vKeyNames ' + vKeyNames.length); 73 | device.log('vKeyPositions ' + vKeyPositions.length); 74 | } 75 | 76 | export function Initialize() 77 | { 78 | requestFirmwareType(); 79 | requestQMKVersion(); 80 | requestSignalRGBProtocolVersion(); 81 | requestUniqueIdentifier(); 82 | requestTotalLeds(); 83 | effectEnable(); 84 | 85 | } 86 | 87 | export function Render() 88 | { 89 | sendColors(); 90 | } 91 | 92 | export function Shutdown(SystemSuspending) 93 | { 94 | 95 | if(SystemSuspending) 96 | { 97 | sendColors("#000000"); // Go Dark on System Sleep/Shutdown 98 | } 99 | else 100 | { 101 | if (shutdownMode === "SignalRGB") 102 | { 103 | sendColors(shutdownColor); 104 | } 105 | else 106 | { 107 | effectDisable(); 108 | } 109 | } 110 | //vKeysArrayCount(); // For debugging array counts 111 | 112 | } 113 | 114 | function commandHandler() 115 | { 116 | const readCounts = []; 117 | 118 | do 119 | { 120 | const returnpacket = device.read([0x00], 32, 10); 121 | processCommands(returnpacket); 122 | 123 | readCounts.push(device.getLastReadSize()); 124 | 125 | // Extra Read to throw away empty packets from Via 126 | // Via always sends a second packet with the same Command Id. 127 | if(IsViaKeyboard) 128 | { 129 | device.read([0x00], 32, 10); 130 | } 131 | } 132 | while(device.getLastReadSize() > 0); 133 | 134 | } 135 | 136 | function processCommands(data) 137 | { 138 | switch(data[1]) 139 | { 140 | case 0x21: 141 | returnQMKVersion(data); 142 | break; 143 | case 0x22: 144 | returnSignalRGBProtocolVersion(data); 145 | break; 146 | case 0x23: 147 | returnUniqueIdentifier(data); 148 | break; 149 | case 0x24: 150 | sendColors(); 151 | break; 152 | case 0x27: 153 | returnTotalLeds(data); 154 | break; 155 | case 0x28: 156 | returnFirmwareType(data); 157 | break; 158 | } 159 | } 160 | 161 | function requestQMKVersion() //Check the version of QMK Firmware that the keyboard is running 162 | { 163 | device.write([0x00, 0x21], 32); 164 | device.pause(30); 165 | commandHandler(); 166 | } 167 | 168 | function returnQMKVersion(data) 169 | { 170 | const QMKVersionByte1 = data[2]; 171 | const QMKVersionByte2 = data[3]; 172 | const QMKVersionByte3 = data[4]; 173 | device.log("QMK Version: " + QMKVersionByte1 + "." + QMKVersionByte2 + "." + QMKVersionByte3); 174 | device.log("QMK SRGB Plugin Version: "+ Version()); 175 | device.pause(30); 176 | } 177 | 178 | function requestSignalRGBProtocolVersion() //Grab the version of the SignalRGB Protocol the keyboard is running 179 | { 180 | device.write([0x00, 0x22], 32); 181 | device.pause(30); 182 | commandHandler(); 183 | } 184 | 185 | function returnSignalRGBProtocolVersion(data) 186 | { 187 | const ProtocolVersionByte1 = data[2]; 188 | const ProtocolVersionByte2 = data[3]; 189 | const ProtocolVersionByte3 = data[4]; 190 | 191 | const SignalRGBProtocolVersion = ProtocolVersionByte1 + "." + ProtocolVersionByte2 + "." + ProtocolVersionByte3; 192 | device.log(`SignalRGB Protocol Version: ${SignalRGBProtocolVersion}`); 193 | 194 | 195 | if(PluginProtocolVersion !== SignalRGBProtocolVersion) 196 | { 197 | device.notify("Unsupported Protocol Version", `This plugin is intended for SignalRGB Protocol version ${PluginProtocolVersion}. This device is version: ${SignalRGBProtocolVersion}`, 2, "Documentation"); 198 | } 199 | 200 | device.pause(30); 201 | } 202 | 203 | function requestUniqueIdentifier() //Grab the unique identifier for this keyboard model 204 | { 205 | if(device.write([0x00, 0x23], 32) === -1) 206 | { 207 | device.notify("Unsupported Firmware", "This device is not running SignalRGB-compatible firmware. Click the Documentation button to learn more.", 3, "Documentation"); 208 | } 209 | 210 | device.pause(30); 211 | commandHandler(); 212 | } 213 | 214 | 215 | function returnUniqueIdentifier(data) 216 | { 217 | const UniqueIdentifierByte1 = data[2]; 218 | const UniqueIdentifierByte2 = data[3]; 219 | const UniqueIdentifierByte3 = data[4]; 220 | 221 | if(!(UniqueIdentifierByte1 === 0 && UniqueIdentifierByte2 === 0 && UniqueIdentifierByte3 === 0)) 222 | { 223 | device.log("Unique Device Identifier: " + UniqueIdentifierByte1 + UniqueIdentifierByte2 + UniqueIdentifierByte3); 224 | } 225 | 226 | device.pause(30); 227 | } 228 | 229 | function requestTotalLeds() //Calculate total number of LEDs 230 | { 231 | device.write([0x00, 0x27], 32); 232 | device.pause(30); 233 | commandHandler(); 234 | } 235 | 236 | function returnTotalLeds(data) 237 | { 238 | LEDCount = data[2]; 239 | device.log("Device Total LED Count: " + LEDCount); 240 | device.pause(30); 241 | } 242 | 243 | function requestFirmwareType() 244 | { 245 | device.write([0x00, 0x28], 32); 246 | device.pause(30); 247 | commandHandler(); 248 | } 249 | 250 | function returnFirmwareType(data) 251 | { 252 | const FirmwareTypeByte = data[2]; 253 | 254 | if(!(FirmwareTypeByte === MainlineQMKFirmware || FirmwareTypeByte === VIAFirmware)) 255 | { 256 | device.notify("Unsupported Firmware", "Click the Documentation button to learn more.", 3, "Documentation"); 257 | } 258 | 259 | if(FirmwareTypeByte === MainlineQMKFirmware) 260 | { 261 | IsViaKeyboard = false; 262 | device.log("Firmware Type: Mainline"); 263 | } 264 | 265 | if(FirmwareTypeByte === VIAFirmware) 266 | { 267 | IsViaKeyboard = true; 268 | device.log("Firmware Type: VIA"); 269 | } 270 | 271 | device.pause(30); 272 | } 273 | 274 | function effectEnable() //Enable the SignalRGB Effect Mode 275 | { 276 | device.write([0x00, 0x25], 32); 277 | device.pause(30); 278 | } 279 | 280 | function effectDisable() //Revert to Hardware Mode 281 | { 282 | device.write([0x00, 0x26], 32); 283 | device.pause(30); 284 | } 285 | 286 | function createSolidColorArray(color) 287 | { 288 | const rgbdata = new Array(vKeys.length * 3).fill(0); 289 | 290 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 291 | { 292 | const iLedIdx = vKeys[iIdx] * 3; 293 | rgbdata[iLedIdx] = color[0]; 294 | rgbdata[iLedIdx+1] = color[1]; 295 | rgbdata[iLedIdx+2] = color[2]; 296 | } 297 | 298 | return rgbdata; 299 | } 300 | 301 | function grabColors(overrideColor) 302 | { 303 | if(overrideColor) 304 | { 305 | return createSolidColorArray(hexToRgb(overrideColor)); 306 | } 307 | else if (LightingMode === "Forced") 308 | { 309 | return createSolidColorArray(hexToRgb(forcedColor)); 310 | } 311 | 312 | const rgbdata = new Array(vKeys.length * 3).fill(0); 313 | 314 | for(let iIdx = 0; iIdx < vKeys.length; iIdx++) 315 | { 316 | const iPxX = vKeyPositions[iIdx][0]; 317 | const iPxY = vKeyPositions[iIdx][1]; 318 | let color = device.color(iPxX, iPxY); 319 | 320 | const iLedIdx = vKeys[iIdx] * 3; 321 | rgbdata[iLedIdx] = color[0]; 322 | rgbdata[iLedIdx+1] = color[1]; 323 | rgbdata[iLedIdx+2] = color[2]; 324 | } 325 | 326 | return rgbdata; 327 | } 328 | 329 | function sendColors(overrideColor) 330 | { 331 | const rgbdata = grabColors(overrideColor); 332 | 333 | const LedsPerPacket = 9; 334 | let BytesSent = 0; 335 | let BytesLeft = rgbdata.length; 336 | 337 | while(BytesLeft > 0) 338 | { 339 | const BytesToSend = Math.min(LedsPerPacket * 3, BytesLeft); 340 | StreamLightingData(Math.floor(BytesSent / 3), rgbdata.splice(0, BytesToSend)); 341 | 342 | BytesLeft -= BytesToSend; 343 | BytesSent += BytesToSend; 344 | } 345 | } 346 | 347 | function StreamLightingData(StartLedIdx, RGBData) 348 | { 349 | const packet = [0x00, 0x24, StartLedIdx, Math.floor(RGBData.length / 3)].concat(RGBData); 350 | device.write(packet, 33); 351 | } 352 | 353 | function hexToRgb(hex) 354 | { 355 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 356 | const colors = []; 357 | colors[0] = parseInt(result[1], 16); 358 | colors[1] = parseInt(result[2], 16); 359 | colors[2] = parseInt(result[3], 16); 360 | 361 | return colors; 362 | } 363 | 364 | export function Validate(endpoint) 365 | { 366 | return endpoint.interface === 1; 367 | } 368 | --------------------------------------------------------------------------------