├── .gitignore ├── .npmignore ├── LICENSE ├── package-lock.json ├── package.json ├── readme.md ├── src ├── index.ts ├── nhk │ ├── KeyCodeToPrintableChar.ts │ ├── NodeHotKey.ts │ ├── RunMacro.ts │ └── index.ts └── utils │ ├── Clipboard.ts │ ├── KeyboardMouse.ts │ ├── Keycodes.ts │ ├── Wait.ts │ ├── Window.ts │ └── index.ts ├── tsconfig.json ├── tslint.json └── types ├── nhk-types.d.ts └── robot-js.d.ts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | node_modules 3 | tsconfig.json 4 | yarn.lock -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Rubinder Singh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodehotkey", 3 | "version": "2.0.15", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.0.0", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", 10 | "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.0.0" 14 | } 15 | }, 16 | "@babel/highlight": { 17 | "version": "7.0.0", 18 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", 19 | "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", 20 | "dev": true, 21 | "requires": { 22 | "chalk": "^2.0.0", 23 | "esutils": "^2.0.2", 24 | "js-tokens": "^4.0.0" 25 | } 26 | }, 27 | "@types/node": { 28 | "version": "10.12.21", 29 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.21.tgz", 30 | "integrity": "sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ==", 31 | "dev": true 32 | }, 33 | "abbrev": { 34 | "version": "1.1.1", 35 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 36 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" 37 | }, 38 | "ajv": { 39 | "version": "4.11.8", 40 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", 41 | "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", 42 | "requires": { 43 | "co": "^4.6.0", 44 | "json-stable-stringify": "^1.0.1" 45 | } 46 | }, 47 | "ansi-regex": { 48 | "version": "2.1.1", 49 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 50 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" 51 | }, 52 | "ansi-styles": { 53 | "version": "3.2.1", 54 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 55 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 56 | "dev": true, 57 | "requires": { 58 | "color-convert": "^1.9.0" 59 | } 60 | }, 61 | "aproba": { 62 | "version": "1.2.0", 63 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", 64 | "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" 65 | }, 66 | "are-we-there-yet": { 67 | "version": "1.1.5", 68 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", 69 | "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", 70 | "requires": { 71 | "delegates": "^1.0.0", 72 | "readable-stream": "^2.0.6" 73 | } 74 | }, 75 | "argparse": { 76 | "version": "1.0.10", 77 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 78 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 79 | "dev": true, 80 | "requires": { 81 | "sprintf-js": "~1.0.2" 82 | } 83 | }, 84 | "asn1": { 85 | "version": "0.2.4", 86 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 87 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 88 | "requires": { 89 | "safer-buffer": "~2.1.0" 90 | } 91 | }, 92 | "assert-plus": { 93 | "version": "0.2.0", 94 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", 95 | "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" 96 | }, 97 | "asynckit": { 98 | "version": "0.4.0", 99 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 100 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 101 | }, 102 | "aws-sign2": { 103 | "version": "0.6.0", 104 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", 105 | "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" 106 | }, 107 | "aws4": { 108 | "version": "1.8.0", 109 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", 110 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" 111 | }, 112 | "balanced-match": { 113 | "version": "1.0.0", 114 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 115 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 116 | }, 117 | "bcrypt-pbkdf": { 118 | "version": "1.0.2", 119 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 120 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 121 | "requires": { 122 | "tweetnacl": "^0.14.3" 123 | } 124 | }, 125 | "block-stream": { 126 | "version": "0.0.9", 127 | "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", 128 | "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", 129 | "requires": { 130 | "inherits": "~2.0.0" 131 | } 132 | }, 133 | "boom": { 134 | "version": "2.10.1", 135 | "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", 136 | "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", 137 | "requires": { 138 | "hoek": "2.x.x" 139 | } 140 | }, 141 | "brace-expansion": { 142 | "version": "1.1.11", 143 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 144 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 145 | "requires": { 146 | "balanced-match": "^1.0.0", 147 | "concat-map": "0.0.1" 148 | } 149 | }, 150 | "builtin-modules": { 151 | "version": "1.1.1", 152 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 153 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 154 | "dev": true 155 | }, 156 | "caseless": { 157 | "version": "0.12.0", 158 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 159 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 160 | }, 161 | "chalk": { 162 | "version": "2.4.2", 163 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 164 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 165 | "dev": true, 166 | "requires": { 167 | "ansi-styles": "^3.2.1", 168 | "escape-string-regexp": "^1.0.5", 169 | "supports-color": "^5.3.0" 170 | } 171 | }, 172 | "co": { 173 | "version": "4.6.0", 174 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 175 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" 176 | }, 177 | "code-point-at": { 178 | "version": "1.1.0", 179 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 180 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" 181 | }, 182 | "color-convert": { 183 | "version": "1.9.3", 184 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 185 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 186 | "dev": true, 187 | "requires": { 188 | "color-name": "1.1.3" 189 | } 190 | }, 191 | "color-name": { 192 | "version": "1.1.3", 193 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 194 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 195 | "dev": true 196 | }, 197 | "colors": { 198 | "version": "1.1.2", 199 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", 200 | "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=" 201 | }, 202 | "combined-stream": { 203 | "version": "1.0.7", 204 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", 205 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", 206 | "requires": { 207 | "delayed-stream": "~1.0.0" 208 | } 209 | }, 210 | "commander": { 211 | "version": "2.20.0", 212 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", 213 | "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", 214 | "dev": true 215 | }, 216 | "concat-map": { 217 | "version": "0.0.1", 218 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 219 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 220 | }, 221 | "console-control-strings": { 222 | "version": "1.1.0", 223 | "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", 224 | "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" 225 | }, 226 | "core-util-is": { 227 | "version": "1.0.2", 228 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 229 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 230 | }, 231 | "cross-env": { 232 | "version": "5.2.0", 233 | "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz", 234 | "integrity": "sha512-jtdNFfFW1hB7sMhr/H6rW1Z45LFqyI431m3qU6bFXcQ3Eh7LtBuG3h74o7ohHZ3crrRkkqHlo4jYHFPcjroANg==", 235 | "dev": true, 236 | "requires": { 237 | "cross-spawn": "^6.0.5", 238 | "is-windows": "^1.0.0" 239 | } 240 | }, 241 | "cross-spawn": { 242 | "version": "6.0.5", 243 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 244 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 245 | "dev": true, 246 | "requires": { 247 | "nice-try": "^1.0.4", 248 | "path-key": "^2.0.1", 249 | "semver": "^5.5.0", 250 | "shebang-command": "^1.2.0", 251 | "which": "^1.2.9" 252 | }, 253 | "dependencies": { 254 | "semver": { 255 | "version": "5.6.0", 256 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", 257 | "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", 258 | "dev": true 259 | } 260 | } 261 | }, 262 | "cryptiles": { 263 | "version": "2.0.5", 264 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", 265 | "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", 266 | "requires": { 267 | "boom": "2.x.x" 268 | } 269 | }, 270 | "dashdash": { 271 | "version": "1.14.1", 272 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 273 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 274 | "requires": { 275 | "assert-plus": "^1.0.0" 276 | }, 277 | "dependencies": { 278 | "assert-plus": { 279 | "version": "1.0.0", 280 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 281 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 282 | } 283 | } 284 | }, 285 | "delayed-stream": { 286 | "version": "1.0.0", 287 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 288 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 289 | }, 290 | "delegates": { 291 | "version": "1.0.0", 292 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", 293 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" 294 | }, 295 | "diff": { 296 | "version": "3.5.0", 297 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 298 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 299 | "dev": true 300 | }, 301 | "ecc-jsbn": { 302 | "version": "0.1.2", 303 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 304 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 305 | "requires": { 306 | "jsbn": "~0.1.0", 307 | "safer-buffer": "^2.1.0" 308 | } 309 | }, 310 | "escape-string-regexp": { 311 | "version": "1.0.5", 312 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 313 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 314 | "dev": true 315 | }, 316 | "esprima": { 317 | "version": "4.0.1", 318 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 319 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 320 | "dev": true 321 | }, 322 | "esutils": { 323 | "version": "2.0.2", 324 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 325 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 326 | "dev": true 327 | }, 328 | "extend": { 329 | "version": "3.0.2", 330 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 331 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 332 | }, 333 | "extsprintf": { 334 | "version": "1.3.0", 335 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 336 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 337 | }, 338 | "forever-agent": { 339 | "version": "0.6.1", 340 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 341 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 342 | }, 343 | "form-data": { 344 | "version": "2.1.4", 345 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", 346 | "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", 347 | "requires": { 348 | "asynckit": "^0.4.0", 349 | "combined-stream": "^1.0.5", 350 | "mime-types": "^2.1.12" 351 | } 352 | }, 353 | "fs.realpath": { 354 | "version": "1.0.0", 355 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 356 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 357 | }, 358 | "fstream": { 359 | "version": "1.0.11", 360 | "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", 361 | "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", 362 | "requires": { 363 | "graceful-fs": "^4.1.2", 364 | "inherits": "~2.0.0", 365 | "mkdirp": ">=0.5 0", 366 | "rimraf": "2" 367 | } 368 | }, 369 | "gauge": { 370 | "version": "2.7.4", 371 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", 372 | "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", 373 | "requires": { 374 | "aproba": "^1.0.3", 375 | "console-control-strings": "^1.0.0", 376 | "has-unicode": "^2.0.0", 377 | "object-assign": "^4.1.0", 378 | "signal-exit": "^3.0.0", 379 | "string-width": "^1.0.1", 380 | "strip-ansi": "^3.0.1", 381 | "wide-align": "^1.1.0" 382 | } 383 | }, 384 | "getpass": { 385 | "version": "0.1.7", 386 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 387 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 388 | "requires": { 389 | "assert-plus": "^1.0.0" 390 | }, 391 | "dependencies": { 392 | "assert-plus": { 393 | "version": "1.0.0", 394 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 395 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 396 | } 397 | } 398 | }, 399 | "glob": { 400 | "version": "7.1.3", 401 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 402 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 403 | "requires": { 404 | "fs.realpath": "^1.0.0", 405 | "inflight": "^1.0.4", 406 | "inherits": "2", 407 | "minimatch": "^3.0.4", 408 | "once": "^1.3.0", 409 | "path-is-absolute": "^1.0.0" 410 | } 411 | }, 412 | "graceful-fs": { 413 | "version": "4.1.15", 414 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", 415 | "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" 416 | }, 417 | "har-schema": { 418 | "version": "1.0.5", 419 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", 420 | "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" 421 | }, 422 | "har-validator": { 423 | "version": "4.2.1", 424 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", 425 | "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", 426 | "requires": { 427 | "ajv": "^4.9.1", 428 | "har-schema": "^1.0.5" 429 | } 430 | }, 431 | "has-flag": { 432 | "version": "3.0.0", 433 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 434 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 435 | "dev": true 436 | }, 437 | "has-unicode": { 438 | "version": "2.0.1", 439 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", 440 | "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" 441 | }, 442 | "hawk": { 443 | "version": "3.1.3", 444 | "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", 445 | "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", 446 | "requires": { 447 | "boom": "2.x.x", 448 | "cryptiles": "2.x.x", 449 | "hoek": "2.x.x", 450 | "sntp": "1.x.x" 451 | } 452 | }, 453 | "hoek": { 454 | "version": "2.16.3", 455 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", 456 | "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" 457 | }, 458 | "http-signature": { 459 | "version": "1.1.1", 460 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", 461 | "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", 462 | "requires": { 463 | "assert-plus": "^0.2.0", 464 | "jsprim": "^1.2.2", 465 | "sshpk": "^1.7.0" 466 | } 467 | }, 468 | "inflight": { 469 | "version": "1.0.6", 470 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 471 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 472 | "requires": { 473 | "once": "^1.3.0", 474 | "wrappy": "1" 475 | } 476 | }, 477 | "inherits": { 478 | "version": "2.0.3", 479 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 480 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 481 | }, 482 | "is-fullwidth-code-point": { 483 | "version": "1.0.0", 484 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 485 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 486 | "requires": { 487 | "number-is-nan": "^1.0.0" 488 | } 489 | }, 490 | "is-typedarray": { 491 | "version": "1.0.0", 492 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 493 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 494 | }, 495 | "is-windows": { 496 | "version": "1.0.2", 497 | "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", 498 | "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", 499 | "dev": true 500 | }, 501 | "isarray": { 502 | "version": "1.0.0", 503 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 504 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 505 | }, 506 | "isexe": { 507 | "version": "2.0.0", 508 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 509 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" 510 | }, 511 | "isstream": { 512 | "version": "0.1.2", 513 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 514 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 515 | }, 516 | "js-tokens": { 517 | "version": "4.0.0", 518 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 519 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 520 | "dev": true 521 | }, 522 | "js-yaml": { 523 | "version": "3.13.1", 524 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 525 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 526 | "dev": true, 527 | "requires": { 528 | "argparse": "^1.0.7", 529 | "esprima": "^4.0.0" 530 | } 531 | }, 532 | "jsbn": { 533 | "version": "0.1.1", 534 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 535 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 536 | }, 537 | "json-schema": { 538 | "version": "0.2.3", 539 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 540 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 541 | }, 542 | "json-stable-stringify": { 543 | "version": "1.0.1", 544 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", 545 | "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", 546 | "requires": { 547 | "jsonify": "~0.0.0" 548 | } 549 | }, 550 | "json-stringify-safe": { 551 | "version": "5.0.1", 552 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 553 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 554 | }, 555 | "jsonify": { 556 | "version": "0.0.0", 557 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", 558 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" 559 | }, 560 | "jsprim": { 561 | "version": "1.4.1", 562 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 563 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 564 | "requires": { 565 | "assert-plus": "1.0.0", 566 | "extsprintf": "1.3.0", 567 | "json-schema": "0.2.3", 568 | "verror": "1.10.0" 569 | }, 570 | "dependencies": { 571 | "assert-plus": { 572 | "version": "1.0.0", 573 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 574 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 575 | } 576 | } 577 | }, 578 | "mime-db": { 579 | "version": "1.38.0", 580 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", 581 | "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" 582 | }, 583 | "mime-types": { 584 | "version": "2.1.22", 585 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", 586 | "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", 587 | "requires": { 588 | "mime-db": "~1.38.0" 589 | } 590 | }, 591 | "minimatch": { 592 | "version": "3.0.4", 593 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 594 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 595 | "requires": { 596 | "brace-expansion": "^1.1.7" 597 | } 598 | }, 599 | "minimist": { 600 | "version": "0.0.8", 601 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 602 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 603 | }, 604 | "mkdirp": { 605 | "version": "0.5.1", 606 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 607 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 608 | "requires": { 609 | "minimist": "0.0.8" 610 | } 611 | }, 612 | "nice-try": { 613 | "version": "1.0.5", 614 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 615 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", 616 | "dev": true 617 | }, 618 | "node-gyp": { 619 | "version": "3.6.3", 620 | "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.3.tgz", 621 | "integrity": "sha512-7789TDMqJpv5iHxn1cAESCBEC/sBHAFxAvgXAcvzWenEWl0qf6E2Kk/Xwdl5ZclktUJzxJPVa27OMkBvaHKqCQ==", 622 | "requires": { 623 | "fstream": "^1.0.0", 624 | "glob": "^7.0.3", 625 | "graceful-fs": "^4.1.2", 626 | "minimatch": "^3.0.2", 627 | "mkdirp": "^0.5.0", 628 | "nopt": "2 || 3", 629 | "npmlog": "0 || 1 || 2 || 3 || 4", 630 | "osenv": "0", 631 | "request": ">=2.9.0 <2.82.0", 632 | "rimraf": "2", 633 | "semver": "~5.3.0", 634 | "tar": "^2.0.0", 635 | "which": "1" 636 | } 637 | }, 638 | "nopt": { 639 | "version": "3.0.6", 640 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", 641 | "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", 642 | "requires": { 643 | "abbrev": "1" 644 | } 645 | }, 646 | "npmlog": { 647 | "version": "4.1.2", 648 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", 649 | "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", 650 | "requires": { 651 | "are-we-there-yet": "~1.1.2", 652 | "console-control-strings": "~1.1.0", 653 | "gauge": "~2.7.3", 654 | "set-blocking": "~2.0.0" 655 | } 656 | }, 657 | "number-is-nan": { 658 | "version": "1.0.1", 659 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 660 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" 661 | }, 662 | "oauth-sign": { 663 | "version": "0.8.2", 664 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", 665 | "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" 666 | }, 667 | "object-assign": { 668 | "version": "4.1.1", 669 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 670 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 671 | }, 672 | "once": { 673 | "version": "1.4.0", 674 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 675 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 676 | "requires": { 677 | "wrappy": "1" 678 | } 679 | }, 680 | "os-homedir": { 681 | "version": "1.0.2", 682 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 683 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" 684 | }, 685 | "os-tmpdir": { 686 | "version": "1.0.2", 687 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 688 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" 689 | }, 690 | "osenv": { 691 | "version": "0.1.5", 692 | "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", 693 | "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", 694 | "requires": { 695 | "os-homedir": "^1.0.0", 696 | "os-tmpdir": "^1.0.0" 697 | } 698 | }, 699 | "path-is-absolute": { 700 | "version": "1.0.1", 701 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 702 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 703 | }, 704 | "path-key": { 705 | "version": "2.0.1", 706 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 707 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 708 | "dev": true 709 | }, 710 | "path-parse": { 711 | "version": "1.0.6", 712 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 713 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 714 | "dev": true 715 | }, 716 | "performance-now": { 717 | "version": "0.2.0", 718 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", 719 | "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" 720 | }, 721 | "process-nextick-args": { 722 | "version": "2.0.0", 723 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 724 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" 725 | }, 726 | "punycode": { 727 | "version": "1.4.1", 728 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 729 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 730 | }, 731 | "qs": { 732 | "version": "6.4.0", 733 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", 734 | "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" 735 | }, 736 | "readable-stream": { 737 | "version": "2.3.6", 738 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 739 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 740 | "requires": { 741 | "core-util-is": "~1.0.0", 742 | "inherits": "~2.0.3", 743 | "isarray": "~1.0.0", 744 | "process-nextick-args": "~2.0.0", 745 | "safe-buffer": "~5.1.1", 746 | "string_decoder": "~1.1.1", 747 | "util-deprecate": "~1.0.1" 748 | } 749 | }, 750 | "request": { 751 | "version": "2.81.0", 752 | "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", 753 | "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", 754 | "requires": { 755 | "aws-sign2": "~0.6.0", 756 | "aws4": "^1.2.1", 757 | "caseless": "~0.12.0", 758 | "combined-stream": "~1.0.5", 759 | "extend": "~3.0.0", 760 | "forever-agent": "~0.6.1", 761 | "form-data": "~2.1.1", 762 | "har-validator": "~4.2.1", 763 | "hawk": "~3.1.3", 764 | "http-signature": "~1.1.0", 765 | "is-typedarray": "~1.0.0", 766 | "isstream": "~0.1.2", 767 | "json-stringify-safe": "~5.0.1", 768 | "mime-types": "~2.1.7", 769 | "oauth-sign": "~0.8.1", 770 | "performance-now": "^0.2.0", 771 | "qs": "~6.4.0", 772 | "safe-buffer": "^5.0.1", 773 | "stringstream": "~0.0.4", 774 | "tough-cookie": "~2.3.0", 775 | "tunnel-agent": "^0.6.0", 776 | "uuid": "^3.0.0" 777 | } 778 | }, 779 | "resolve": { 780 | "version": "1.11.0", 781 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz", 782 | "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==", 783 | "dev": true, 784 | "requires": { 785 | "path-parse": "^1.0.6" 786 | } 787 | }, 788 | "rimraf": { 789 | "version": "2.6.3", 790 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 791 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 792 | "requires": { 793 | "glob": "^7.1.3" 794 | } 795 | }, 796 | "robot-js": { 797 | "version": "2.0.0", 798 | "resolved": "https://registry.npmjs.org/robot-js/-/robot-js-2.0.0.tgz", 799 | "integrity": "sha512-6tuHtFwoklo2vPf88R8xTEZC1S5T3OyXgLTUgXtAERzCnp2UOW2DEENoy1x62zADIrNmvJp29xyTJ2RMdos1YQ==", 800 | "requires": { 801 | "colors": "~1.1", 802 | "node-gyp": "~3.6" 803 | } 804 | }, 805 | "safe-buffer": { 806 | "version": "5.1.2", 807 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 808 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 809 | }, 810 | "safer-buffer": { 811 | "version": "2.1.2", 812 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 813 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 814 | }, 815 | "semver": { 816 | "version": "5.3.0", 817 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", 818 | "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" 819 | }, 820 | "set-blocking": { 821 | "version": "2.0.0", 822 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 823 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" 824 | }, 825 | "shebang-command": { 826 | "version": "1.2.0", 827 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 828 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 829 | "dev": true, 830 | "requires": { 831 | "shebang-regex": "^1.0.0" 832 | } 833 | }, 834 | "shebang-regex": { 835 | "version": "1.0.0", 836 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 837 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 838 | "dev": true 839 | }, 840 | "signal-exit": { 841 | "version": "3.0.2", 842 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 843 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" 844 | }, 845 | "sntp": { 846 | "version": "1.0.9", 847 | "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", 848 | "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", 849 | "requires": { 850 | "hoek": "2.x.x" 851 | } 852 | }, 853 | "sprintf-js": { 854 | "version": "1.0.3", 855 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 856 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 857 | "dev": true 858 | }, 859 | "sshpk": { 860 | "version": "1.16.1", 861 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 862 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 863 | "requires": { 864 | "asn1": "~0.2.3", 865 | "assert-plus": "^1.0.0", 866 | "bcrypt-pbkdf": "^1.0.0", 867 | "dashdash": "^1.12.0", 868 | "ecc-jsbn": "~0.1.1", 869 | "getpass": "^0.1.1", 870 | "jsbn": "~0.1.0", 871 | "safer-buffer": "^2.0.2", 872 | "tweetnacl": "~0.14.0" 873 | }, 874 | "dependencies": { 875 | "assert-plus": { 876 | "version": "1.0.0", 877 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 878 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 879 | } 880 | } 881 | }, 882 | "string-width": { 883 | "version": "1.0.2", 884 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 885 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 886 | "requires": { 887 | "code-point-at": "^1.0.0", 888 | "is-fullwidth-code-point": "^1.0.0", 889 | "strip-ansi": "^3.0.0" 890 | } 891 | }, 892 | "string_decoder": { 893 | "version": "1.1.1", 894 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 895 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 896 | "requires": { 897 | "safe-buffer": "~5.1.0" 898 | } 899 | }, 900 | "stringstream": { 901 | "version": "0.0.6", 902 | "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", 903 | "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==" 904 | }, 905 | "strip-ansi": { 906 | "version": "3.0.1", 907 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 908 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 909 | "requires": { 910 | "ansi-regex": "^2.0.0" 911 | } 912 | }, 913 | "supports-color": { 914 | "version": "5.5.0", 915 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 916 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 917 | "dev": true, 918 | "requires": { 919 | "has-flag": "^3.0.0" 920 | } 921 | }, 922 | "tar": { 923 | "version": "2.2.1", 924 | "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", 925 | "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", 926 | "requires": { 927 | "block-stream": "*", 928 | "fstream": "^1.0.2", 929 | "inherits": "2" 930 | } 931 | }, 932 | "tough-cookie": { 933 | "version": "2.3.4", 934 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", 935 | "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", 936 | "requires": { 937 | "punycode": "^1.4.1" 938 | } 939 | }, 940 | "tslib": { 941 | "version": "1.10.0", 942 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", 943 | "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", 944 | "dev": true 945 | }, 946 | "tslint": { 947 | "version": "5.17.0", 948 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.17.0.tgz", 949 | "integrity": "sha512-pflx87WfVoYepTet3xLfDOLDm9Jqi61UXIKePOuca0qoAZyrGWonDG9VTbji58Fy+8gciUn8Bt7y69+KEVjc/w==", 950 | "dev": true, 951 | "requires": { 952 | "@babel/code-frame": "^7.0.0", 953 | "builtin-modules": "^1.1.1", 954 | "chalk": "^2.3.0", 955 | "commander": "^2.12.1", 956 | "diff": "^3.2.0", 957 | "glob": "^7.1.1", 958 | "js-yaml": "^3.13.1", 959 | "minimatch": "^3.0.4", 960 | "mkdirp": "^0.5.1", 961 | "resolve": "^1.3.2", 962 | "semver": "^5.3.0", 963 | "tslib": "^1.8.0", 964 | "tsutils": "^2.29.0" 965 | } 966 | }, 967 | "tsutils": { 968 | "version": "2.29.0", 969 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 970 | "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", 971 | "dev": true, 972 | "requires": { 973 | "tslib": "^1.8.1" 974 | } 975 | }, 976 | "tunnel-agent": { 977 | "version": "0.6.0", 978 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 979 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 980 | "requires": { 981 | "safe-buffer": "^5.0.1" 982 | } 983 | }, 984 | "tweetnacl": { 985 | "version": "0.14.5", 986 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 987 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 988 | }, 989 | "util-deprecate": { 990 | "version": "1.0.2", 991 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 992 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 993 | }, 994 | "uuid": { 995 | "version": "3.3.2", 996 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 997 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 998 | }, 999 | "verror": { 1000 | "version": "1.10.0", 1001 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 1002 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 1003 | "requires": { 1004 | "assert-plus": "^1.0.0", 1005 | "core-util-is": "1.0.2", 1006 | "extsprintf": "^1.2.0" 1007 | }, 1008 | "dependencies": { 1009 | "assert-plus": { 1010 | "version": "1.0.0", 1011 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 1012 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 1013 | } 1014 | } 1015 | }, 1016 | "which": { 1017 | "version": "1.3.1", 1018 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1019 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1020 | "requires": { 1021 | "isexe": "^2.0.0" 1022 | } 1023 | }, 1024 | "wide-align": { 1025 | "version": "1.1.3", 1026 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", 1027 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", 1028 | "requires": { 1029 | "string-width": "^1.0.2 || 2" 1030 | } 1031 | }, 1032 | "wrappy": { 1033 | "version": "1.0.2", 1034 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1035 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1036 | } 1037 | } 1038 | } 1039 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodehotkey", 3 | "version": "2.0.15", 4 | "description": "Authotkey like macros for NodeJS", 5 | "main": "build/index.js", 6 | "types": "build/index.d.ts", 7 | "scripts": { 8 | "prepublish": "npm run build && npm run defs", 9 | "build": "tsc", 10 | "defs": "tsc --declaration --outDir build --emitDeclarationOnly" 11 | }, 12 | "author": "Rubinder Singh", 13 | "license": "MIT", 14 | "dependencies": { 15 | "robot-js": "2.0.0" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "10.12.21", 19 | "cross-env": "5.2.0", 20 | "tslint": "^5.17.0" 21 | }, 22 | "engines": { 23 | "node": "0.12 - 9" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/Rubinder25/NodeHotKey" 28 | }, 29 | "keywords": [ 30 | "autohotkey", 31 | "nodehotkey", 32 | "automation", 33 | "macro", 34 | "macros", 35 | "robot", 36 | "robot-js", 37 | "hotkeys", 38 | "hotkey", 39 | "hotstrings", 40 | "hotstring", 41 | "clipboard", 42 | "keyboard", 43 | "mouse" 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ![GitHub](https://img.shields.io/github/license/rubinder25/NodeHotKey.svg?style=flat-square) 2 | ![GitHub package.json version](https://img.shields.io/github/package-json/v/Rubinder25/NodeHotKey.svg?style=flat-square) 3 | 4 | # NodeHotKey 5 | https://github.com/Rubinder25/NodeHotKey 6 | https://www.npmjs.com/package/nodehotkey 7 | This is an autohotkey like library for NodeJs 8 | 9 | ## Features 10 | 11 | 1. Make global Macros and assign hotkeys to trigger them 12 | 2. Make global hotstrings to expand text as you type it 13 | 3. Catch global keyboard/mouse events in your code 14 | 4. Operate keyboard, mouse and clipboard from code 15 | # Usage 16 | ## Install 17 | `npm install nodehotkey --save` 18 | follow this page to install dependencies for robot-js on your platform: http://getrobot.net/docs/usage.html 19 | 20 | ## import 21 | `import { NodeHotKey } from 'nodehotkey';` 22 | ## Initialize the object 23 | ```javascript 24 | let nhk = new NodeHotKey({}); 25 | ``` 26 | Currently, we are passing an empty object. A Macro Config object can be passed to the constructor in order to create AutoHotkey like macros. 27 | Please refer to the next section for this. 28 | 29 | ## Macro 30 | Macros are pre-defined steps that can be triggered by either pressing hotkeys or typing hotstrings. These can be defined as JavaScript objects. 31 | ### A sample macro looks like this 32 | ```javascript 33 | let macroConfig = { 34 | 'Name of the Macro': { 35 | hotkeys: [kc._CONTROL, kc._E], 36 | steps: [ 37 | { type: 'This Macro can be triggered by pressing CTRL+E\n' }, 38 | { type: "Wait for 3 secs then press ',' " }, 39 | { wait: 3000 }, 40 | { click: kc._COMMA }, 41 | { func: tools => { 42 | tools.type('Run JavaScript functions by pressing hotkeys'); 43 | } 44 | } 45 | ] 46 | } 47 | } 48 | ``` 49 | we can then pass this macroConfig to constructor of NodeHotKey like this:- 50 | ```javascript 51 | let nhk = new NodeHotKey(macroConfig); 52 | nhk.startListening(); 53 | ``` 54 | 55 | For more sample Marco configs check out **[MacroSamples_NodeHotKey](https://github.com/Rubinder25/MacroSamples_NodeHotKey)**. 56 | ## Events 57 | ```javascript 58 | nhk.on(nhk.eventTypes.keyPressed, (eventData) => { 59 | console.log('KeyPressed ', eventData.keyCode); 60 | }); 61 | ``` 62 | ## Functions 63 | following are the utility functions present in the package:- 64 | ```javascript 65 | import { pressKey, releaseKey, click, 66 | type, paste, wait, setClipboardText, 67 | getClipboardText, matchCurrentWindowTitle } from 'nodehotkey'; 68 | ``` 69 | ## Putting it all together 70 | 71 | ```javascript 72 | import { NodeHotKey, pressKey,releaseKey, KEYCODES as kc } from 'nodehotkey'; 73 | 74 | // press key 75 | pressKey(kc._A); 76 | releaseKey(kc._A); 77 | 78 | let macroConfig = { 79 | 'Name of the Macro': { 80 | hotkeys: [kc._CONTROL, kc._E], 81 | steps: [ 82 | { type: 'This Macro can be triggered by pressing CTRL+E\n' }, 83 | { type: "Wait for 3 secs then press ',' " }, 84 | { wait: 3000 }, 85 | { click: kc._COMMA }, 86 | { func: tools => { 87 | tools.type('Run JavaScript functions by pressing hotkeys'); 88 | } 89 | } 90 | ] 91 | } 92 | } 93 | 94 | let nhk = new NodeHotKey(macroConfig); 95 | 96 | nhk.startListening(); 97 | 98 | nhk.on(nhk.eventTypes.keyPressed, (eventData) => { 99 | console.log('KeyPressed ', eventData.keyCode); 100 | }); 101 | 102 | // nhk.stopListening(); // terminates the program 103 | ``` 104 | ## Sample Macros 105 | https://github.com/Rubinder25/MacroSamples_NodeHotKey 106 | 107 | > email: mail2rubinder@gmail.com 108 | 109 | ## License 110 | MIT 111 | 112 | **Note:** currently Node V10 is not supported 113 | 114 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './nhk/NodeHotKey'; 2 | export * from './utils'; 3 | export * from '../types/nhk-types'; 4 | -------------------------------------------------------------------------------- /src/nhk/KeyCodeToPrintableChar.ts: -------------------------------------------------------------------------------- 1 | export function keyCodeToPrintableChar(keyNumber: number, isShiftOn: boolean): string { 2 | // 47 keys 3 | interface IKey2PrintMap { 4 | [key: number]: { 5 | shiftOff: string; 6 | shiftOn: string; 7 | }; 8 | } 9 | 10 | const key2PrintMap: IKey2PrintMap = { 11 | 48: { 12 | shiftOff: '0', 13 | shiftOn: ')', 14 | }, 15 | 49: { 16 | shiftOff: '1', 17 | shiftOn: '!', 18 | }, 19 | 50: { 20 | shiftOff: '2', 21 | shiftOn: '@', 22 | }, 23 | 51: { 24 | shiftOff: '3', 25 | shiftOn: '#', 26 | }, 27 | 52: { 28 | shiftOff: '4', 29 | shiftOn: '$', 30 | }, 31 | 53: { 32 | shiftOff: '5', 33 | shiftOn: '%', 34 | }, 35 | 54: { 36 | shiftOff: '6', 37 | shiftOn: '^', 38 | }, 39 | 55: { 40 | shiftOff: '7', 41 | shiftOn: '&', 42 | }, 43 | 56: { 44 | shiftOff: '8', 45 | shiftOn: '*', 46 | }, 47 | 57: { 48 | shiftOff: '9', 49 | shiftOn: '(', 50 | }, 51 | 65: { 52 | shiftOff: 'a', 53 | shiftOn: 'A', 54 | }, 55 | 66: { 56 | shiftOff: 'b', 57 | shiftOn: 'B', 58 | }, 59 | 67: { 60 | shiftOff: 'c', 61 | shiftOn: 'C', 62 | }, 63 | 68: { 64 | shiftOff: 'd', 65 | shiftOn: 'D', 66 | }, 67 | 69: { 68 | shiftOff: 'e', 69 | shiftOn: 'E', 70 | }, 71 | 70: { 72 | shiftOff: 'f', 73 | shiftOn: 'F', 74 | }, 75 | 71: { 76 | shiftOff: 'g', 77 | shiftOn: 'G', 78 | }, 79 | 72: { 80 | shiftOff: 'h', 81 | shiftOn: 'H', 82 | }, 83 | 73: { 84 | shiftOff: 'i', 85 | shiftOn: 'I', 86 | }, 87 | 74: { 88 | shiftOff: 'j', 89 | shiftOn: 'J', 90 | }, 91 | 75: { 92 | shiftOff: 'k', 93 | shiftOn: 'K', 94 | }, 95 | 76: { 96 | shiftOff: 'l', 97 | shiftOn: 'L', 98 | }, 99 | 77: { 100 | shiftOff: 'm', 101 | shiftOn: 'M', 102 | }, 103 | 78: { 104 | shiftOff: 'n', 105 | shiftOn: 'N', 106 | }, 107 | 79: { 108 | shiftOff: 'o', 109 | shiftOn: 'O', 110 | }, 111 | 80: { 112 | shiftOff: 'p', 113 | shiftOn: 'P', 114 | }, 115 | 81: { 116 | shiftOff: 'q', 117 | shiftOn: 'Q', 118 | }, 119 | 82: { 120 | shiftOff: 'r', 121 | shiftOn: 'R', 122 | }, 123 | 83: { 124 | shiftOff: 's', 125 | shiftOn: 'S', 126 | }, 127 | 84: { 128 | shiftOff: 't', 129 | shiftOn: 'T', 130 | }, 131 | 85: { 132 | shiftOff: 'u', 133 | shiftOn: 'U', 134 | }, 135 | 86: { 136 | shiftOff: 'v', 137 | shiftOn: 'V', 138 | }, 139 | 87: { 140 | shiftOff: 'w', 141 | shiftOn: 'W', 142 | }, 143 | 88: { 144 | shiftOff: 'x', 145 | shiftOn: 'X', 146 | }, 147 | 89: { 148 | shiftOff: 'y', 149 | shiftOn: 'Y', 150 | }, 151 | 90: { 152 | shiftOff: 'z', 153 | shiftOn: 'Z', 154 | }, 155 | 186: { 156 | shiftOff: ';', 157 | shiftOn: ':', 158 | }, 159 | 187: { 160 | shiftOff: '=', 161 | shiftOn: '+', 162 | }, 163 | 188: { 164 | shiftOff: ',', 165 | shiftOn: '<', 166 | }, 167 | 189: { 168 | shiftOff: '-', 169 | shiftOn: '_', 170 | }, 171 | 190: { 172 | shiftOff: '.', 173 | shiftOn: '>', 174 | }, 175 | 191: { 176 | shiftOff: '/', 177 | shiftOn: '?', 178 | }, 179 | 192: { 180 | shiftOff: '`', 181 | shiftOn: '~', 182 | }, 183 | 219: { 184 | shiftOff: '[', 185 | shiftOn: '{', 186 | }, 187 | 220: { 188 | shiftOff: '\\', 189 | shiftOn: '|', 190 | }, 191 | 221: { 192 | shiftOff: ']', 193 | shiftOn: '}', 194 | }, 195 | 222: { 196 | shiftOff: '\'', 197 | shiftOn: '\'', 198 | }, 199 | }; 200 | 201 | const keyMap = key2PrintMap[keyNumber]; 202 | 203 | if (keyMap) { 204 | return isShiftOn ? keyMap.shiftOn : keyMap.shiftOff; 205 | } else { 206 | return ''; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/nhk/NodeHotKey.ts: -------------------------------------------------------------------------------- 1 | /******************************************************************************************* 2 | * * 3 | * ███╗ ██╗ ██████╗ ██████╗ ███████╗██╗ ██╗ ██████╗ ████████╗██╗ ██╗███████╗██╗ ██╗ * 4 | * ████╗ ██║██╔═══██╗██╔══██╗██╔════╝██║ ██║██╔═══██╗╚══██╔══╝██║ ██╔╝██╔════╝╚██╗ ██╔╝ * 5 | * ██╔██╗ ██║██║ ██║██║ ██║█████╗ ███████║██║ ██║ ██║ █████╔╝ █████╗ ╚████╔╝ * 6 | * ██║╚██╗██║██║ ██║██║ ██║██╔══╝ ██╔══██║██║ ██║ ██║ ██╔═██╗ ██╔══╝ ╚██╔╝ * 7 | * ██║ ╚████║╚██████╔╝██████╔╝███████╗██║ ██║╚██████╔╝ ██║ ██║ ██╗███████╗ ██║ * 8 | * * 9 | * Title: NodeHotKey * 10 | * Author: Rubinder Singh * 11 | * Date: 07-Jun-2019 * 12 | *******************************************************************************************/ 13 | 14 | import { ConditionsType, KeyStateType, MacroType } from '../../types/nhk-types'; 15 | import { click, releaseKey } from '../utils/KeyboardMouse'; 16 | import { KEYCODES } from '../utils/Keycodes'; 17 | import { matchCurrentWindowTitle } from '../utils/Window'; 18 | import { keyCodeToPrintableChar } from './KeyCodeToPrintableChar'; 19 | import { runMacro } from './RunMacro'; 20 | // tslint:disable-next-line: no-var-requires 21 | const EventEmitter = require('events'); 22 | 23 | export class NodeHotKey extends EventEmitter { 24 | /** 25 | * start listening for keyboard, mouse and Macro events 26 | * @returns {void} 27 | */ 28 | public startListening: () => void; 29 | 30 | /** 31 | * stop listening for keyboard and mouse events 32 | * @returns {void} 33 | */ 34 | public stopListening: () => void; 35 | 36 | public readonly eventTypes: { [key: string]: string }; 37 | 38 | public constructor(pMacros?: MacroType) { 39 | super(); 40 | const robot = require('robot-js'); 41 | const timer = robot.Timer(); 42 | const doubleKeyCodes = [160, 161, 162, 163, 164, 165]; 43 | 44 | let listeningInterval: NodeJS.Timeout | null; 45 | let macros: MacroType; 46 | let currHotstring: string; 47 | let justRanMacro: boolean; 48 | let isRobotOn: boolean; 49 | let keyboardStatePrev: any; 50 | let keyboardStateCurr: any; 51 | let mouseStatePrev: any; 52 | let mouseStateCurr: any; 53 | const emptyMacrosObject = { 54 | EmptyMacro: { steps: [] }, 55 | }; 56 | 57 | const eventTypes = { 58 | hotKeyTriggered: 'hotKeyTriggered', 59 | hotstringTriggered: 'hotstringTriggered', 60 | keyPressed: 'keyPressed', 61 | keyReleased: 'keyReleased', 62 | loopTriggered: 'loopTriggered', 63 | mouseKeyPressed: 'mouseKeyPressed', 64 | mouseKeyReleased: 'mouseKeyReleased', 65 | }; 66 | const emit = this.emit.bind(this); 67 | const on = this.on.bind(this); 68 | 69 | macros = pMacros || emptyMacrosObject; 70 | listeningInterval = null; 71 | currHotstring = ''; 72 | justRanMacro = false; 73 | isRobotOn = false; 74 | 75 | function checkRobotOn(keyCode: string) { 76 | let timeElapsed = 0; 77 | // if key is in exception list don't run the function and simply return false 78 | // e.g. for Shift keycodes 16, 160 and 161 all are triggred together which may cause misleading results 79 | if (doubleKeyCodes.indexOf(Number(keyCode)) !== -1) { 80 | return false; 81 | } 82 | 83 | if (keyboardStatePrev[keyCode] !== keyboardStateCurr[keyCode]) { 84 | if (timer.hasStarted()) { 85 | timeElapsed = timer.getElapsed(); 86 | timer.reset(); 87 | } 88 | timer.start(); 89 | if (process.env.NODE_ENV === 'dev') { 90 | console.log('Timer elapsed:', timeElapsed); 91 | } 92 | 93 | if (timeElapsed < 10) { 94 | // the keys are being pressed by robot 95 | return true; 96 | } else { 97 | // the keys are being pressed by human 98 | return false; 99 | } 100 | } 101 | return false; 102 | } 103 | 104 | function emitEvent(eventType: string, outConsole: string, eventData: any) { 105 | emit(eventType, eventData); 106 | if (process.env.NODE_ENV === 'dev') { 107 | console.log(eventType + ':', outConsole); 108 | } 109 | } 110 | 111 | function startLoops() { 112 | Object.keys(macros).forEach((key) => { 113 | const macro = macros[key]; 114 | if (macro.loop) { 115 | setInterval(() => { 116 | if (matchMacroConditions(macro.conditions)) { 117 | emitEvent(eventTypes.loopTriggered, key, { 118 | loopInterval: macro.loop, 119 | macroName: key, 120 | }); 121 | runMacro(macro.steps); 122 | } 123 | }, macro.loop * 1000); 124 | } 125 | }); 126 | } 127 | 128 | function isKeyPressed(keyStatePrev: KeyStateType, keyStateCurr: KeyStateType, keyCode: string): boolean { 129 | if (keyStatePrev[keyCode] === false && keyStateCurr[keyCode] === true) { 130 | return true; 131 | } 132 | return false; 133 | } 134 | 135 | function isKeyReleased(keyStatePrev: KeyStateType, keyStateCurr: KeyStateType, keyCode: string): boolean { 136 | if (keyStatePrev[keyCode] === true && keyStateCurr[keyCode] === false) { 137 | return true; 138 | } 139 | return false; 140 | } 141 | 142 | function keyboardPressReleaseEvents(keyStatePrev: KeyStateType, keyStateCurr: KeyStateType, keyCode: string): void { 143 | 144 | // key pressed 145 | if (isKeyPressed(keyStatePrev, keyStateCurr, keyCode)) { 146 | emitEvent(eventTypes.keyPressed, `${keyCode} pressed`, { 147 | keyBoardState: keyStateCurr, 148 | keyCode, 149 | printableChar: keyCodeToPrintableChar(Number(keyCode), keyStateCurr[KEYCODES._SHIFT]), 150 | }); 151 | } 152 | 153 | // key released 154 | if (isKeyReleased(keyStatePrev, keyStateCurr, keyCode)) { 155 | emitEvent(eventTypes.keyReleased, `${keyCode} released`, { 156 | keyBoardState: keyStateCurr, 157 | keyCode, 158 | printableChar: keyCodeToPrintableChar(Number(keyCode), keyStateCurr[KEYCODES._SHIFT]), 159 | }); 160 | } 161 | } 162 | 163 | function mousePressReleaseEvents(keyStatePrev: KeyStateType, keyStateCurr: KeyStateType, keyCode: string): void { 164 | // key pressed 165 | if (isKeyPressed(keyStatePrev, keyStateCurr, keyCode)) { 166 | emitEvent(eventTypes.keyPressed, `${keyCode} pressed`, 167 | { 168 | keyBoardState: keyStateCurr, 169 | keyCode, 170 | printableChar: keyCodeToPrintableChar(Number(keyCode), keyStateCurr[KEYCODES._SHIFT]), 171 | }); 172 | } 173 | // key released 174 | if (isKeyReleased(keyStatePrev, keyStateCurr, keyCode)) { 175 | emitEvent(eventTypes.keyReleased, `${keyCode} released`, 176 | { 177 | keyBoardState: keyStateCurr, 178 | keyCode, 179 | printableChar: keyCodeToPrintableChar(Number(keyCode), keyStateCurr[KEYCODES._SHIFT]), 180 | }); 181 | } 182 | } 183 | 184 | function matchMacroConditions(conditions: ConditionsType | undefined): boolean { 185 | // if conditions are not specified always return true 186 | if (conditions === undefined) { 187 | return true; 188 | } 189 | 190 | // start matching all the conditions one by one 191 | if (conditions.window && !matchCurrentWindowTitle(conditions.window)) { 192 | return false; 193 | } 194 | 195 | return true; 196 | } 197 | 198 | function detectHotKeyEvents() { 199 | function areKeysPressed(keyCodeArr: number[], keyState: any, mouseState: any): boolean { 200 | let keysArePressed = true; 201 | keyCodeArr.forEach((keyCode) => { 202 | if (!keyState[keyCode] && !mouseState[keyCode]) { 203 | keysArePressed = false; 204 | } 205 | }); 206 | return keysArePressed; 207 | } 208 | 209 | if (justRanMacro === false) { 210 | Object.keys(macros).forEach((key) => { 211 | const macro = macros[key]; 212 | if ( 213 | macro.hotkeys && 214 | areKeysPressed(macro.hotkeys, keyboardStateCurr, mouseStateCurr) && 215 | matchMacroConditions(macro.conditions) 216 | ) { 217 | emitEvent( 218 | eventTypes.hotKeyTriggered, `${key}`, { 219 | macroName: key, 220 | }); 221 | 222 | justRanMacro = true; 223 | setTimeout(() => { 224 | justRanMacro = false; 225 | }, 500); 226 | 227 | doubleKeyCodes.forEach((keyCode) => releaseKey(keyCode)); 228 | macro.hotkeys.forEach((keyCode) => releaseKey(keyCode)); 229 | runMacro(macro.steps); 230 | } 231 | }); 232 | } 233 | } 234 | 235 | function detectHotstringEvents(keyCode: string, isShiftOn: boolean): void { 236 | // update currHotstring 237 | const keyPressedCodeNumber = Number(keyCode); 238 | const char: string = keyCodeToPrintableChar(keyPressedCodeNumber, isShiftOn); 239 | // shift key is exception for hotstring capture 240 | if (char === '' && keyPressedCodeNumber !== 16 && keyPressedCodeNumber !== 160 && keyPressedCodeNumber !== 161) { 241 | currHotstring = ''; 242 | } else { 243 | currHotstring += char; 244 | } 245 | 246 | if (process.env.NODE_ENV === 'dev') { 247 | console.log('Hostring recorded:', currHotstring); 248 | } 249 | 250 | // match currHotstring in macros 251 | Object.keys(macros).forEach((key) => { 252 | const macro = macros[key]; 253 | if ( 254 | macro.hotstring && 255 | macro.hotstring === currHotstring && 256 | matchMacroConditions(macro.conditions) 257 | ) { 258 | doubleKeyCodes.forEach((code) => { releaseKey(code); }); 259 | currHotstring = ''; 260 | 261 | if (macro.steps[0].type !== undefined || macro.steps[0].paste !== undefined) { 262 | // tslint:disable-next-line:prefer-for-of 263 | for (let i = 0; i < macro.hotstring.length; i++) { 264 | click(KEYCODES._BACKSPACE); 265 | } 266 | } 267 | 268 | emitEvent(eventTypes.hotstringTriggered, macro.hotstring, { 269 | hotString: macro.hotstring, 270 | macroName: key, 271 | }); 272 | runMacro(macro.steps); 273 | } 274 | }); 275 | } 276 | 277 | function startListening() { 278 | keyboardStatePrev = robot.Keyboard.getState(); 279 | mouseStatePrev = robot.Mouse.getState(); 280 | 281 | on(eventTypes.keyPressed, (eventData: any) => { 282 | // Hotstrings 283 | if (!isRobotOn) { 284 | detectHotstringEvents(eventData.keyCode, eventData.keyBoardState[KEYCODES._SHIFT]); 285 | } else { 286 | currHotstring = ''; 287 | } 288 | }); 289 | 290 | // Loops 291 | startLoops(); 292 | 293 | listeningInterval = setInterval(() => { 294 | // keyboard 295 | keyboardStateCurr = robot.Keyboard.getState(); 296 | Object.keys(keyboardStateCurr).forEach((keyCode: string) => { 297 | isRobotOn = checkRobotOn(keyCode); 298 | keyboardPressReleaseEvents(keyboardStatePrev, keyboardStateCurr, keyCode); 299 | }); 300 | keyboardStatePrev = keyboardStateCurr; 301 | 302 | // Mouse 303 | mouseStateCurr = robot.Mouse.getState(); 304 | Object.keys(mouseStateCurr).forEach((keyCode: string) => { 305 | mousePressReleaseEvents(mouseStateCurr, mouseStatePrev, keyCode); 306 | }); 307 | mouseStatePrev = mouseStateCurr; 308 | 309 | // Macros 310 | if (!isRobotOn) { 311 | // hotkeys 312 | detectHotKeyEvents(); 313 | } 314 | 315 | }, 0); 316 | } 317 | 318 | function stopListening() { 319 | if (listeningInterval) { 320 | clearInterval(listeningInterval); 321 | } 322 | } 323 | 324 | this.startListening = startListening; 325 | this.stopListening = stopListening; 326 | this.eventTypes = eventTypes; 327 | } 328 | } 329 | -------------------------------------------------------------------------------- /src/nhk/RunMacro.ts: -------------------------------------------------------------------------------- 1 | import { MacroStepType } from '../../types/nhk-types'; 2 | import { getClipboardText, setClipboardText } from '../utils/Clipboard'; 3 | import { click, paste, pressKey, releaseKey, type } from '../utils/KeyboardMouse'; 4 | import { wait } from '../utils/Wait'; 5 | import { matchCurrentWindowTitle } from '../utils/Window'; 6 | 7 | export function runMacro(steps: MacroStepType[]) { 8 | 9 | steps.forEach((step) => { 10 | if (step.pressKey !== undefined) { 11 | const keyCode = step.pressKey; 12 | pressKey(keyCode); 13 | } 14 | 15 | if (step.releaseKey !== undefined) { 16 | const keyCode = step.releaseKey; 17 | releaseKey(keyCode); 18 | } 19 | 20 | if (step.type !== undefined) { 21 | const s = step.type; 22 | type(s); 23 | } 24 | 25 | if (step.click !== undefined) { 26 | click(step.click); 27 | } 28 | 29 | if (step.wait !== undefined) { 30 | const delay = step.wait; 31 | wait(delay); 32 | } 33 | 34 | if (step.paste !== undefined) { 35 | const text = step.paste; 36 | paste(text); 37 | } 38 | 39 | if (step.func !== undefined) { 40 | step.func({ pressKey, releaseKey, click, type, paste, wait, setClipboardText, getClipboardText, matchCurrentWindowTitle }); 41 | } 42 | 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /src/nhk/index.ts: -------------------------------------------------------------------------------- 1 | export * from './NodeHotKey'; 2 | export * from './KeyCodeToPrintableChar'; 3 | -------------------------------------------------------------------------------- /src/utils/Clipboard.ts: -------------------------------------------------------------------------------- 1 | import robot from 'robot-js'; 2 | 3 | /** 4 | * get text from the clipboard 5 | * @returns {string} 6 | */ 7 | export function getClipboardText(): string { 8 | return robot.Clipboard.getText(); 9 | } 10 | 11 | /** 12 | * set text to clipboard 13 | * @param text {string} text to set to clipboard 14 | * @returns {void} 15 | */ 16 | export function setClipboardText(text: string): void { 17 | robot.Clipboard.setText(text); 18 | } 19 | -------------------------------------------------------------------------------- /src/utils/KeyboardMouse.ts: -------------------------------------------------------------------------------- 1 | import robot from 'robot-js'; 2 | import { ClickType } from '../../types/nhk-types'; 3 | import { getClipboardText, setClipboardText } from './Clipboard'; 4 | import { KEYCODES as KC } from './Keycodes'; 5 | import { wait } from './Wait'; 6 | 7 | const keyboard = robot.Keyboard(); 8 | keyboard.autoDelay.min = 0; 9 | keyboard.autoDelay.max = 0; 10 | 11 | const mouse = robot.Mouse(); 12 | mouse.autoDelay.min = 0; 13 | mouse.autoDelay.max = 0; 14 | 15 | /** 16 | * press a keyboard/mouse key 17 | * @param keyCode {number} code of the key to press 18 | * @returns {void} 19 | */ 20 | export function pressKey(keyCode: number): void { 21 | keyCode < 8 ? mouse.press(keyCode) : keyboard.press(keyCode); 22 | } 23 | 24 | /** 25 | * release a keyboard/mouse key 26 | * @param keyCode {number} code of the key to release 27 | * @returns {void} 28 | */ 29 | export function releaseKey(keyCode: number): void { 30 | keyCode < 8 ? mouse.release(keyCode) : keyboard.release(keyCode); 31 | } 32 | 33 | /** 34 | * click a keyboard/mouse key 35 | * @param clickKey {ClickType} 36 | * @returns {void} 37 | */ 38 | export function click(clickKey: ClickType | number | number[]): void { 39 | const pressReleaseKeys = (keyCodes: number | number[]): void => { 40 | // convert keyCodes into an array if its a number 41 | keyCodes = typeof keyCodes === 'number' ? [keyCodes] : keyCodes; 42 | 43 | keyCodes.forEach((keyCode) => { 44 | pressKey(keyCode); 45 | releaseKey(keyCode); 46 | }); 47 | }; 48 | 49 | if (typeof clickKey === 'number' || Array.isArray(clickKey)) { 50 | pressReleaseKeys(clickKey); 51 | } else if (typeof clickKey === 'object') { 52 | for (let i = 0; i < (clickKey.times || 1); i++) { 53 | if (clickKey.modifiers) { 54 | // convert modifiers into an array if its a number 55 | const modifiers = typeof clickKey.modifiers === 'number' ? [clickKey.modifiers] : clickKey.modifiers; 56 | 57 | modifiers.forEach((modifier) => pressKey(modifier)); 58 | pressReleaseKeys(clickKey.key); 59 | modifiers.forEach((modifier) => releaseKey(modifier)); 60 | } else { 61 | pressReleaseKeys(clickKey.key); 62 | } 63 | } 64 | } 65 | } 66 | 67 | /** 68 | * pastes given text 69 | * @param string {text} text to be pasted 70 | * @returns {void} 71 | */ 72 | export function paste(text: string): void { 73 | const tempClipText = getClipboardText(); 74 | const delay = 200; 75 | 76 | setClipboardText(text); 77 | wait(delay); 78 | click({ key: KC._V, modifiers: [KC._CONTROL] }); 79 | wait(delay); 80 | setClipboardText(tempClipText); 81 | } 82 | 83 | /** 84 | * type string using keystrokes 85 | * @param text {string} string to be typed 86 | * @returns {void} 87 | */ 88 | export function type(text: string): void { 89 | const getMapping = (c: string): string => { 90 | switch (c) { 91 | case ' ': 92 | return ' '; 93 | case '!': 94 | return '+1'; 95 | case '"': 96 | return '+\''; 97 | case '#': 98 | return '+3'; 99 | case '$': 100 | return '+4'; 101 | case '%': 102 | return '+5'; 103 | case '&': 104 | return '+7'; 105 | case '\'': 106 | return '\''; 107 | case '(': 108 | return '+9'; 109 | case ')': 110 | return '+0'; 111 | case '*': 112 | return '+8'; 113 | case '+': 114 | return '+='; 115 | case ',': 116 | return ','; 117 | case '-': 118 | return '-'; 119 | case '.': 120 | return '.'; 121 | case '/': 122 | return '/'; 123 | case '0': 124 | return '0'; 125 | case '1': 126 | return '1'; 127 | case '2': 128 | return '2'; 129 | case '3': 130 | return '3'; 131 | case '4': 132 | return '4'; 133 | case '5': 134 | return '5'; 135 | case '6': 136 | return '6'; 137 | case '7': 138 | return '7'; 139 | case '8': 140 | return '8'; 141 | case '9': 142 | return '9'; 143 | case ':': 144 | return '+;'; 145 | case ';': 146 | return ';'; 147 | case '<': 148 | return '+,'; 149 | case '=': 150 | return '='; 151 | case '>': 152 | return '+.'; 153 | case '?': 154 | return '=/'; 155 | case '@': 156 | return '+2'; 157 | case 'A': 158 | return '+a'; 159 | case 'B': 160 | return '+b'; 161 | case 'C': 162 | return '+c'; 163 | case 'D': 164 | return '+d'; 165 | case 'E': 166 | return '+e'; 167 | case 'F': 168 | return '+f'; 169 | case 'G': 170 | return '+g'; 171 | case 'H': 172 | return '+h'; 173 | case 'I': 174 | return '+i'; 175 | case 'J': 176 | return '+j'; 177 | case 'K': 178 | return '+k'; 179 | case 'L': 180 | return '+l'; 181 | case 'M': 182 | return '+m'; 183 | case 'N': 184 | return '+n'; 185 | case 'O': 186 | return '+o'; 187 | case 'P': 188 | return '+p'; 189 | case 'Q': 190 | return '+q'; 191 | case 'R': 192 | return '+r'; 193 | case 'S': 194 | return '+s'; 195 | case 'T': 196 | return '+t'; 197 | case 'U': 198 | return '+u'; 199 | case 'V': 200 | return '+v'; 201 | case 'W': 202 | return '+w'; 203 | case 'X': 204 | return '+x'; 205 | case 'Y': 206 | return '+y'; 207 | case 'Z': 208 | return '+z'; 209 | case '[': 210 | return '['; 211 | case '\\': 212 | return '\\'; 213 | case ']': 214 | return ']'; 215 | case '^': 216 | return '+6'; 217 | case '_': 218 | return '+-'; 219 | case '`': 220 | return '`'; 221 | case 'a': 222 | return 'a'; 223 | case 'b': 224 | return 'b'; 225 | case 'c': 226 | return 'c'; 227 | case 'd': 228 | return 'd'; 229 | case 'e': 230 | return 'e'; 231 | case 'f': 232 | return 'f'; 233 | case 'g': 234 | return 'g'; 235 | case 'h': 236 | return 'h'; 237 | case 'i': 238 | return 'i'; 239 | case 'j': 240 | return 'j'; 241 | case 'k': 242 | return 'k'; 243 | case 'l': 244 | return 'l'; 245 | case 'm': 246 | return 'm'; 247 | case 'n': 248 | return 'n'; 249 | case 'o': 250 | return 'o'; 251 | case 'p': 252 | return 'p'; 253 | case 'q': 254 | return 'q'; 255 | case 'r': 256 | return 'r'; 257 | case 's': 258 | return 's'; 259 | case 't': 260 | return 't'; 261 | case 'u': 262 | return 'u'; 263 | case 'v': 264 | return 'v'; 265 | case 'w': 266 | return 'w'; 267 | case 'x': 268 | return 'x'; 269 | case 'y': 270 | return 'y'; 271 | case 'z': 272 | return 'z'; 273 | case '{': 274 | return '+['; 275 | case '|': 276 | return '+\\'; 277 | case '}': 278 | return '+]'; 279 | case '~': 280 | return '+`'; 281 | case '\n': 282 | return '{Enter}'; 283 | case '': 284 | return ' '; 285 | default: 286 | return ''; 287 | } 288 | }; 289 | 290 | keyboard.click( 291 | text 292 | .split('') 293 | .map((c) => getMapping(c)) 294 | .join(''), 295 | ); 296 | } 297 | -------------------------------------------------------------------------------- /src/utils/Keycodes.ts: -------------------------------------------------------------------------------- 1 | import robot from 'robot-js'; 2 | 3 | export const KEYCODES = { 4 | _0: robot.KEY_0, 5 | _1: robot.KEY_1, 6 | _2: robot.KEY_2, 7 | _3: robot.KEY_3, 8 | _4: robot.KEY_4, 9 | _5: robot.KEY_5, 10 | _6: robot.KEY_6, 11 | _7: robot.KEY_7, 12 | _8: robot.KEY_8, 13 | _9: robot.KEY_9, 14 | _A: robot.KEY_A, 15 | _B: robot.KEY_B, 16 | _C: robot.KEY_C, 17 | _D: robot.KEY_D, 18 | _E: robot.KEY_E, 19 | _F: robot.KEY_F, 20 | _G: robot.KEY_G, 21 | _H: robot.KEY_H, 22 | _I: robot.KEY_I, 23 | _J: robot.KEY_J, 24 | _K: robot.KEY_K, 25 | _L: robot.KEY_L, 26 | _M: robot.KEY_M, 27 | _N: robot.KEY_N, 28 | _O: robot.KEY_O, 29 | _P: robot.KEY_P, 30 | _Q: robot.KEY_Q, 31 | _R: robot.KEY_R, 32 | _S: robot.KEY_S, 33 | _T: robot.KEY_T, 34 | _U: robot.KEY_U, 35 | _V: robot.KEY_V, 36 | _W: robot.KEY_W, 37 | _X: robot.KEY_X, 38 | _Y: robot.KEY_Y, 39 | _Z: robot.KEY_Z, 40 | _BACKSPACE: robot.KEY_BACKSPACE, 41 | _TAB: robot.KEY_TAB, 42 | _ENTER: robot.KEY_ENTER, 43 | _SHIFT: robot.KEY_SHIFT, 44 | _CONTROL: robot.KEY_CONTROL, 45 | _ALT: robot.KEY_ALT, 46 | _PAUSE: robot.KEY_PAUSE, 47 | _ESC: robot.KEY_ESCAPE, 48 | _SPACE: robot.KEY_SPACE, 49 | _PAGEUP: robot.KEY_PAGE_UP, 50 | _PAGEDOWN: robot.KEY_PAGE_DOWN, 51 | _END: robot.KEY_END, 52 | _HOME: robot.KEY_HOME, 53 | _UP: robot.KEY_UP, 54 | _DOWN: robot.KEY_DOWN, 55 | _LEFT: robot.KEY_LEFT, 56 | _RIGHT: robot.KEY_RIGHT, 57 | _PRINTSCREEN: robot.KEY_PRINT, 58 | _INSERT: robot.KEY_INSERT, 59 | _DELETE: robot.KEY_DELETE, 60 | _WIN: robot.KEY_SYSTEM, 61 | _NUM0: robot.KEY_NUM0, 62 | _NUM1: robot.KEY_NUM1, 63 | _NUM2: robot.KEY_NUM2, 64 | _NUM3: robot.KEY_NUM3, 65 | _NUM4: robot.KEY_NUM4, 66 | _NUM5: robot.KEY_NUM5, 67 | _NUM6: robot.KEY_NUM6, 68 | _NUM7: robot.KEY_NUM7, 69 | _NUM8: robot.KEY_NUM8, 70 | _NUM9: robot.KEY_NUM9, 71 | _MULTIPLY: robot.KEY_MULTIPLY, 72 | _ADD: robot.KEY_ADD, 73 | _SUBTRACT: robot.KEY_SUBTRACT, 74 | _DECIMAL: robot.KEY_DECIMAL, 75 | _DIVIDE: robot.KEY_DIVIDE, 76 | _F1: robot.KEY_F1, 77 | _F2: robot.KEY_F2, 78 | _F3: robot.KEY_F3, 79 | _F4: robot.KEY_F4, 80 | _F5: robot.KEY_F5, 81 | _F6: robot.KEY_F6, 82 | _F7: robot.KEY_F7, 83 | _F8: robot.KEY_F8, 84 | _F9: robot.KEY_F9, 85 | _F10: robot.KEY_F10, 86 | _F11: robot.KEY_F11, 87 | _F12: robot.KEY_F12, 88 | _NUM_LOCK: robot.KEY_NUM_LOCK, 89 | _CAPS_LOCK: robot.KEY_CAPS_LOCK, 90 | _SCROLL_LOCK: robot.KEY_SCROLL_LOCK, 91 | _COMMA: robot.KEY_COMMA, 92 | _UNDER_SCORE: robot.KEY_MINUS, 93 | _EQUAL: robot.KEY_EQUAL, 94 | _PERIOD: robot.KEY_PERIOD, 95 | _FORWARD_SLASH: robot.KEY_SLASH, 96 | _BACK_SLASH: robot.KEY_BACKSLASH, 97 | _RIGHT_BRACKET: robot.KEY_RBRACKET, 98 | _LEFT_BRACKET: robot.KEY_LBRACKET, 99 | _APOSTROPHE: robot.KEY_QUOTE, 100 | _GRAVE: robot.KEY_GRAVE, 101 | _MOUSE_LEFT: robot.BUTTON_LEFT, 102 | _MOUSE_RIGHT: robot.BUTTON_RIGHT, 103 | _MOUSE_MIDDLE: robot.BUTTON_MIDDLE, 104 | _APPS_KEY: 93 105 | }; 106 | -------------------------------------------------------------------------------- /src/utils/Wait.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * waits synchronously 3 | * @param milliseconds {number} time to wait 4 | * @returns {void} 5 | */ 6 | export function wait(milliseconds: number): void { 7 | const currTime = new Date().getTime(); 8 | while (new Date().getTime() < currTime + milliseconds) { 9 | // 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/Window.ts: -------------------------------------------------------------------------------- 1 | import robot from 'robot-js'; 2 | 3 | /** 4 | * checks if current active window's title matches the given string or regexp 5 | * @param title title to match 6 | * @returns {boolean} true the current active window's title matches the given argument 7 | */ 8 | export function matchCurrentWindowTitle(title: string | RegExp): boolean { 9 | const windowTitle: string = robot.Window.getActive().getTitle(); 10 | let titleRegExp: RegExp; 11 | 12 | if (typeof title === 'string') { 13 | titleRegExp = new RegExp(`^${escapeRegExp(title)}$`); 14 | } else if (title instanceof RegExp) { 15 | titleRegExp = title; 16 | } else { 17 | titleRegExp = /.*/g; // make it match everything in unexpected scenario 18 | } 19 | 20 | return windowTitle.match(titleRegExp) !== null; 21 | } 22 | 23 | function escapeRegExp(s: string) { 24 | return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); 25 | } 26 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './KeyboardMouse'; 2 | export * from './Clipboard'; 3 | export * from './Keycodes'; 4 | export * from './Window'; 5 | export * from './Wait'; 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "*": [ 6 | "types/*" 7 | ] 8 | }, 9 | /* Basic Options */ 10 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 11 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 12 | // "lib": [], /* Specify library files to be included in the compilation. */ 13 | // "allowJs": true, /* Allow javascript files to be compiled. */ 14 | // "checkJs": true, /* Report errors in .js files. */ 15 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 16 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 17 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 18 | "sourceMap": true, /* Generates corresponding '.map' file. */ 19 | // "outFile": "./", /* Concatenate and emit output to single file. */ 20 | "outDir": "build", /* Redirect output structure to the directory. */ 21 | "rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 22 | // "composite": true, /* Enable project compilation */ 23 | // "removeComments": true, /* Do not emit comments to output. */ 24 | // "noEmit": true, /* Do not emit outputs. */ 25 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 26 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 27 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 28 | /* Strict Type-Checking Options */ 29 | "strict": true, /* Enable all strict type-checking options. */ 30 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 31 | // "strictNullChecks": true, /* Enable strict null checks. */ 32 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | /* Additional Checks */ 37 | "noUnusedLocals": true, /* Report errors on unused locals. */ 38 | "noUnusedParameters": true, /* Report errors on unused parameters. */ 39 | "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 40 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 41 | /* Module Resolution Options */ 42 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 46 | "typeRoots": [ 47 | // add path to @types 48 | "node_modules/@types" 49 | ], /* List of folders to include type definitions from. */ 50 | "types": [ 51 | "node" 52 | ], /* Type declaration files to be included in compilation. */ 53 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 54 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 55 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 56 | /* Source Map Options */ 57 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 58 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ 59 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 60 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 61 | /* Experimental Options */ 62 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 63 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 64 | } 65 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "linterOptions": { 7 | "exclude": [ 8 | "bin", 9 | "src/utils/Keycodes.ts" 10 | ] 11 | }, 12 | "jsRules": {}, 13 | "rules": { 14 | "quotemark": [ 15 | true, 16 | "single" 17 | ], 18 | "indent": [ 19 | true, 20 | "spaces", 21 | 2 22 | ], 23 | "max-line-length": [ 24 | true, 25 | 150 26 | ], 27 | "no-unused-variable": true, 28 | "no-console": false 29 | }, 30 | "rulesDirectory": [] 31 | } -------------------------------------------------------------------------------- /types/nhk-types.d.ts: -------------------------------------------------------------------------------- 1 | export type MacroType = { 2 | [key: string]: MacroObjectType; 3 | } 4 | 5 | export type MacroObjectType = { 6 | hotkeys?: number[]; 7 | hotstring?: string; 8 | loop?: number; 9 | conditions?: ConditionsType; 10 | steps: MacroStepType[]; 11 | } 12 | 13 | export type ConditionsType = { 14 | window?: string | RegExp; 15 | } 16 | 17 | export type MacroStepType = { 18 | click?: ClickType | number | number[]; 19 | pressKey?: number; 20 | paste?: string; 21 | releaseKey?: number; 22 | type?: string; 23 | wait?: number; 24 | func?: FuncType; 25 | } 26 | 27 | export type ClickType = { 28 | key: number; 29 | modifiers?: number | number[]; 30 | times?: number 31 | } 32 | 33 | export type FuncType = ( 34 | tools: ToolsType 35 | ) => void 36 | 37 | export type ToolsType = { 38 | pressKey: (keyCode: number) => void, 39 | releaseKey: (keyCode: number) => void, 40 | click: (click: ClickType) => void, 41 | type: (text: string) => void, 42 | paste: (text: string) => void, 43 | wait: (milliseconds: number) => void, 44 | setClipboardText: (text: string) => void, 45 | getClipboardText: () => string, 46 | matchCurrentWindowTitle: (title: string | RegExp) => boolean 47 | } 48 | 49 | 50 | export type KeyStateType = { 51 | [key: string]: boolean 52 | } -------------------------------------------------------------------------------- /types/robot-js.d.ts: -------------------------------------------------------------------------------- 1 | export = robot; 2 | declare const robot: any; 3 | --------------------------------------------------------------------------------