macromate-hid 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,310 @@
1
+ # macromate-hid
2
+
3
+ Node.js library for communicating with MacroMate HID device (Pico RP2040-based).
4
+
5
+ ## Features
6
+
7
+ - 🎮 Full keyboard & mouse control via USB HID
8
+ - ⌨️ Key press, release, tap, and string typing
9
+ - 🖱️ Mouse movement, clicks, scrolling
10
+ - ⚡ Promise-based async API
11
+ - 📝 Full TypeScript support
12
+ - 🔧 CLI tool included
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install macromate-hid
18
+ ```
19
+
20
+ Or clone and link locally:
21
+
22
+ ```bash
23
+ cd macromate-hid
24
+ npm install
25
+ npm link
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ```javascript
31
+ const { MacroController, KEY, MOD, MOUSE_BTN } = require('macromate-hid');
32
+
33
+ async function main() {
34
+ const controller = new MacroController();
35
+
36
+ // Connect to device
37
+ controller.connect();
38
+
39
+ // Ping and get version
40
+ const { version } = await controller.ping();
41
+ console.log('Firmware:', version);
42
+
43
+ // Type some text
44
+ await controller.typeString('Hello, World!');
45
+
46
+ // Press Ctrl+S to save
47
+ await controller.shortcut(MOD.CTRL, KEY.S);
48
+
49
+ // Move mouse and click
50
+ await controller.mouseMove(100, 50);
51
+ await controller.mouseClick();
52
+
53
+ // Disconnect
54
+ controller.disconnect();
55
+ }
56
+
57
+ main();
58
+ ```
59
+
60
+ ## API Reference
61
+
62
+ ### Constructor
63
+
64
+ ```javascript
65
+ const controller = new MacroController({
66
+ vid: 0xCAFE, // Vendor ID (default: 0xCAFE)
67
+ pid: 0x4010, // Product ID (default: 0x4010)
68
+ timeout: 2000, // Command timeout in ms (default: 2000)
69
+ debug: false // Enable debug logging (default: false)
70
+ });
71
+ ```
72
+
73
+ ### Connection
74
+
75
+ ```javascript
76
+ // Connect to device
77
+ controller.connect();
78
+
79
+ // Check if connected
80
+ if (controller.isConnected) { ... }
81
+
82
+ // Disconnect
83
+ controller.disconnect();
84
+
85
+ // Find all matching devices
86
+ const devices = MacroController.findDevices();
87
+
88
+ // List all devices with VID
89
+ const allDevices = MacroController.listDevices(0xCAFE);
90
+ ```
91
+
92
+ ### System Commands
93
+
94
+ ```javascript
95
+ // Ping and get firmware version
96
+ const { version } = await controller.ping();
97
+
98
+ // Get version only
99
+ const version = await controller.getVersion();
100
+
101
+ // Enter bootloader mode (device will reboot)
102
+ controller.enterBootloader();
103
+ ```
104
+
105
+ ### Keyboard
106
+
107
+ ```javascript
108
+ // Tap a key (press and release)
109
+ await controller.keyTap(KEY.A);
110
+ await controller.keyTap(KEY.ENTER);
111
+
112
+ // Press and hold a key
113
+ await controller.keyPress(KEY.SPACE);
114
+
115
+ // Release a key
116
+ await controller.keyRelease(KEY.SPACE);
117
+
118
+ // Set modifier keys
119
+ await controller.setModifiers(MOD.CTRL);
120
+ await controller.setModifiers(MOD.CTRL | MOD.SHIFT);
121
+
122
+ // Release all keys and modifiers
123
+ await controller.releaseAll();
124
+
125
+ // Type a string (ASCII, max 62 chars)
126
+ await controller.typeString('Hello!');
127
+
128
+ // Execute keyboard shortcut
129
+ await controller.shortcut(MOD.CTRL, KEY.C); // Ctrl+C
130
+ await controller.shortcut(MOD.CTRL | MOD.SHIFT, KEY.S); // Ctrl+Shift+S
131
+ ```
132
+
133
+ ### Mouse
134
+
135
+ ```javascript
136
+ // Move mouse (relative, -127 to 127)
137
+ await controller.mouseMove(50, -30);
138
+
139
+ // Click
140
+ await controller.mouseClick(); // Left click
141
+ await controller.mouseClick(MOUSE_BTN.RIGHT);
142
+ await controller.mouseClick(MOUSE_BTN.MIDDLE);
143
+
144
+ // Press and hold
145
+ await controller.mousePress(MOUSE_BTN.LEFT);
146
+ await controller.mouseRelease(MOUSE_BTN.LEFT);
147
+
148
+ // Double click
149
+ await controller.mouseDoubleClick();
150
+
151
+ // Scroll (positive = up, negative = down)
152
+ await controller.mouseScroll(3); // Scroll up
153
+ await controller.mouseScroll(-3); // Scroll down
154
+ ```
155
+
156
+ ### Raw Commands
157
+
158
+ ```javascript
159
+ // Send raw command
160
+ const result = await controller.sendCommand(0x00, [0x01, 0x02]);
161
+ console.log(result.status, result.data);
162
+
163
+ // Send command without waiting (for bootloader)
164
+ controller.sendCommandNoWait(0x02);
165
+ ```
166
+
167
+ ## Constants
168
+
169
+ ### KEY - Keyboard Keycodes
170
+
171
+ ```javascript
172
+ const { KEY } = require('macromate-hid');
173
+
174
+ // Letters: KEY.A - KEY.Z
175
+ // Numbers: KEY.N0 - KEY.N9
176
+ // Function: KEY.F1 - KEY.F12
177
+ // Special: KEY.ENTER, KEY.ESC, KEY.BACKSPACE, KEY.TAB, KEY.SPACE
178
+ // Navigation: KEY.UP, KEY.DOWN, KEY.LEFT, KEY.RIGHT
179
+ // Etc: KEY.HOME, KEY.END, KEY.PAGE_UP, KEY.PAGE_DOWN, KEY.DELETE, KEY.INSERT
180
+ ```
181
+
182
+ ### MOD - Modifier Keys
183
+
184
+ ```javascript
185
+ const { MOD } = require('macromate-hid');
186
+
187
+ MOD.CTRL // 0x01
188
+ MOD.SHIFT // 0x02
189
+ MOD.ALT // 0x04
190
+ MOD.WIN // 0x08
191
+
192
+ // Combine with |
193
+ const modifiers = MOD.CTRL | MOD.ALT;
194
+ ```
195
+
196
+ ### MOUSE_BTN - Mouse Buttons
197
+
198
+ ```javascript
199
+ const { MOUSE_BTN } = require('macromate-hid');
200
+
201
+ MOUSE_BTN.LEFT // 0x01
202
+ MOUSE_BTN.RIGHT // 0x02
203
+ MOUSE_BTN.MIDDLE // 0x04
204
+ ```
205
+
206
+ ## CLI Tool
207
+
208
+ After installing, you can use the CLI tool:
209
+
210
+ ```bash
211
+ npx macromate
212
+ # or if linked globally
213
+ macromate
214
+ ```
215
+
216
+ The CLI provides an interactive menu for testing all device functions.
217
+
218
+ ## Examples
219
+
220
+ ### Auto-login Script
221
+
222
+ ```javascript
223
+ const { MacroController, KEY, MOD } = require('macromate-hid');
224
+
225
+ async function autoLogin(username, password) {
226
+ const ctrl = new MacroController();
227
+ ctrl.connect();
228
+
229
+ // Type username
230
+ await ctrl.typeString(username);
231
+ await ctrl.keyTap(KEY.TAB);
232
+
233
+ // Type password
234
+ await ctrl.typeString(password);
235
+ await ctrl.keyTap(KEY.ENTER);
236
+
237
+ ctrl.disconnect();
238
+ }
239
+ ```
240
+
241
+ ### Game Macro
242
+
243
+ ```javascript
244
+ const { MacroController, KEY } = require('macromate-hid');
245
+
246
+ async function burstFire(controller, times = 3) {
247
+ for (let i = 0; i < times; i++) {
248
+ await controller.mouseClick();
249
+ await sleep(50);
250
+ }
251
+ }
252
+
253
+ async function reload(controller) {
254
+ await controller.keyTap(KEY.R);
255
+ }
256
+ ```
257
+
258
+ ### Window Management
259
+
260
+ ```javascript
261
+ const { MacroController, KEY, MOD } = require('macromate-hid');
262
+
263
+ async function switchWindow(controller) {
264
+ // Alt+Tab
265
+ await controller.shortcut(MOD.ALT, KEY.TAB);
266
+ }
267
+
268
+ async function closeWindow(controller) {
269
+ // Alt+F4
270
+ await controller.shortcut(MOD.ALT, KEY.F4);
271
+ }
272
+
273
+ async function lockScreen(controller) {
274
+ // Win+L
275
+ await controller.shortcut(MOD.WIN, KEY.L);
276
+ }
277
+ ```
278
+
279
+ ## Device Setup
280
+
281
+ 1. Flash the MacroMate firmware to your Pico
282
+ 2. Connect via USB
283
+ 3. Device should appear as `VID:CAFE PID:4010`
284
+
285
+ ## Troubleshooting
286
+
287
+ ### Device not found
288
+
289
+ - Make sure device is connected and firmware is flashed
290
+ - Check USB connection
291
+ - On Linux, you may need udev rules for HID access
292
+
293
+ ### Permission denied (Linux)
294
+
295
+ Create udev rule `/etc/udev/rules.d/99-macromate.rules`:
296
+
297
+ ```
298
+ SUBSYSTEM=="usb", ATTR{idVendor}=="cafe", ATTR{idProduct}=="4010", MODE="0666"
299
+ KERNEL=="hidraw*", ATTRS{idVendor}=="cafe", ATTRS{idProduct}=="4010", MODE="0666"
300
+ ```
301
+
302
+ Then reload:
303
+ ```bash
304
+ sudo udevadm control --reload-rules
305
+ sudo udevadm trigger
306
+ ```
307
+
308
+ ## License
309
+
310
+ MIT
package/cli.js ADDED
@@ -0,0 +1,279 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MacroMate CLI - Interactive test tool
4
+ */
5
+
6
+ const readline = require('readline-sync');
7
+ const { MacroController, KEY, MOD, MOUSE_BTN } = require('./src');
8
+
9
+ let controller = null;
10
+
11
+ //--------------------------------------------------------------------
12
+ // HELPERS
13
+ //--------------------------------------------------------------------
14
+
15
+ function confirm(msg) {
16
+ const answer = readline.question(msg + ' (y/n): ').toLowerCase();
17
+ return answer === 'y' || answer === 'yes';
18
+ }
19
+
20
+ function sleep(ms) {
21
+ return new Promise(resolve => setTimeout(resolve, ms));
22
+ }
23
+
24
+ //--------------------------------------------------------------------
25
+ // TESTS
26
+ //--------------------------------------------------------------------
27
+
28
+ async function testPing() {
29
+ console.log('\n--- Test PING ---');
30
+ try {
31
+ const result = await controller.ping();
32
+ console.log(`[OK] Ping successful! Firmware v${result.version}`);
33
+ } catch (e) {
34
+ console.log('[X] Ping failed:', e.message);
35
+ }
36
+ }
37
+
38
+ async function testVersion() {
39
+ console.log('\n--- Get Version ---');
40
+ try {
41
+ const version = await controller.getVersion();
42
+ console.log(`[OK] Version: ${version}`);
43
+ } catch (e) {
44
+ console.log('[X] Failed:', e.message);
45
+ }
46
+ }
47
+
48
+ async function testMouseMove() {
49
+ console.log('\n--- Mouse Move Test ---');
50
+ console.log(' Mouse will move in a small square (50px each side)');
51
+
52
+ if (!confirm(' Continue?')) return;
53
+
54
+ const steps = [[50, 0], [0, 50], [-50, 0], [0, -50]];
55
+ try {
56
+ for (const [x, y] of steps) {
57
+ await controller.mouseMove(x, y);
58
+ await sleep(200);
59
+ }
60
+ console.log('[OK] Mouse move complete');
61
+ } catch (e) {
62
+ console.log('[X] Failed:', e.message);
63
+ }
64
+ }
65
+
66
+ async function testMouseClick() {
67
+ console.log('\n--- Mouse Click Test ---');
68
+ console.log(' WARNING: This will perform a REAL left click!');
69
+ console.log(' Make sure cursor is in a safe place.');
70
+
71
+ if (!confirm(' Click?')) return;
72
+
73
+ try {
74
+ await controller.mouseClick(MOUSE_BTN.LEFT);
75
+ console.log('[OK] Click sent');
76
+ } catch (e) {
77
+ console.log('[X] Failed:', e.message);
78
+ }
79
+ }
80
+
81
+ async function testKeyTap() {
82
+ console.log('\n--- Key Press Test ---');
83
+ console.log(' WARNING: This will type letter "A"!');
84
+ console.log(' Open a text editor and place cursor.');
85
+
86
+ if (!confirm(' Press A?')) return;
87
+
88
+ console.log(' 2 seconds to switch window...');
89
+ await sleep(2000);
90
+
91
+ try {
92
+ await controller.keyTap(KEY.A);
93
+ console.log('[OK] Key tap sent');
94
+ } catch (e) {
95
+ console.log('[X] Failed:', e.message);
96
+ }
97
+ }
98
+
99
+ async function testCombo() {
100
+ console.log('\n--- Combo Test: Ctrl+A ---');
101
+ console.log(' WARNING: This will select all text!');
102
+
103
+ if (!confirm(' Execute Ctrl+A?')) return;
104
+
105
+ console.log(' 2 seconds...');
106
+ await sleep(2000);
107
+
108
+ try {
109
+ await controller.shortcut(MOD.CTRL, KEY.A);
110
+ console.log('[OK] Combo sent');
111
+ } catch (e) {
112
+ console.log('[X] Failed:', e.message);
113
+ }
114
+ }
115
+
116
+ async function testScroll() {
117
+ console.log('\n--- Scroll Test ---');
118
+ console.log(' Scroll up 3 steps');
119
+
120
+ if (!confirm(' Continue?')) return;
121
+
122
+ try {
123
+ for (let i = 0; i < 3; i++) {
124
+ await controller.mouseScroll(1);
125
+ await sleep(100);
126
+ }
127
+ console.log('[OK] Scroll complete');
128
+ } catch (e) {
129
+ console.log('[X] Failed:', e.message);
130
+ }
131
+ }
132
+
133
+ async function testTypeString() {
134
+ console.log('\n--- Type String Test ---');
135
+ console.log(' WARNING: This will type a string!');
136
+ console.log(' Open a text editor and place cursor.');
137
+
138
+ const text = readline.question(' Enter text to type (max 62 chars): ');
139
+ if (!text || text.length === 0) {
140
+ console.log(' Cancelled');
141
+ return;
142
+ }
143
+
144
+ if (!confirm(' Type this string?')) return;
145
+
146
+ console.log(' 2 seconds to switch window...');
147
+ await sleep(2000);
148
+
149
+ try {
150
+ await controller.typeString(text);
151
+ console.log('[OK] String typed');
152
+ } catch (e) {
153
+ console.log('[X] Failed:', e.message);
154
+ }
155
+ }
156
+
157
+ function testBootloader() {
158
+ console.log('\n--- Bootloader Mode ---');
159
+ console.log(' WARNING: Device will reboot into USB flash drive mode!');
160
+ console.log(' You will need to copy new firmware to flash it.');
161
+ console.log(' Connection will be lost.');
162
+
163
+ if (!confirm(' Enter bootloader mode?')) return;
164
+
165
+ controller.enterBootloader();
166
+ console.log('\n Device should now appear as RPI-RP2 drive.');
167
+ console.log(' Copy macromate.uf2 to flash new firmware.');
168
+ }
169
+
170
+ async function manualCommand() {
171
+ console.log('\n--- Manual Command ---');
172
+ console.log(' Enter bytes (hex), e.g.: 00 10 04');
173
+
174
+ const input = readline.question(' > ');
175
+ const bytes = input.split(/\s+/).map(s => parseInt(s, 16)).filter(n => !isNaN(n));
176
+
177
+ if (bytes.length === 0) {
178
+ console.log(' Invalid input');
179
+ return;
180
+ }
181
+
182
+ try {
183
+ await controller.sendCommand(bytes[0], bytes.slice(1));
184
+ console.log('[OK] Command sent');
185
+ } catch (e) {
186
+ console.log('[X] Failed:', e.message);
187
+ }
188
+ }
189
+
190
+ //--------------------------------------------------------------------
191
+ // MENU
192
+ //--------------------------------------------------------------------
193
+
194
+ function showMenu() {
195
+ console.log('\n' + '='.repeat(45));
196
+ console.log(' MACROMATE CLI v1.0');
197
+ console.log('='.repeat(45));
198
+ console.log(' 1. Ping (check connection)');
199
+ console.log(' 2. Get firmware version');
200
+ console.log(' 3. Mouse move (safe)');
201
+ console.log(' 4. Mouse click');
202
+ console.log(' 5. Mouse scroll');
203
+ console.log(' 6. Press key A');
204
+ console.log(' 7. Combo Ctrl+A');
205
+ console.log(' 8. Type string');
206
+ console.log(' 9. Manual command');
207
+ console.log(' r. Reconnect');
208
+ console.log(' b. BOOTLOADER MODE (flash new firmware)');
209
+ console.log(' 0. Exit');
210
+ console.log('='.repeat(45));
211
+ }
212
+
213
+ async function runTest(testFn) {
214
+ try {
215
+ await testFn();
216
+ } catch (e) {
217
+ console.log('[X] Test error:', e.message);
218
+ }
219
+ }
220
+
221
+ async function main() {
222
+ console.log('\n=== MacroMate CLI v1.0 ===\n');
223
+
224
+ // Create controller with debug enabled
225
+ controller = new MacroController({ debug: true });
226
+
227
+ try {
228
+ controller.connect();
229
+ } catch (e) {
230
+ console.log('[X]', e.message);
231
+ console.log('\nFlash the device first and connect it.');
232
+ process.exit(1);
233
+ }
234
+
235
+ while (true) {
236
+ showMenu();
237
+ const choice = readline.question('\nChoice: ');
238
+
239
+ switch (choice) {
240
+ case '1': await runTest(testPing); break;
241
+ case '2': await runTest(testVersion); break;
242
+ case '3': await runTest(testMouseMove); break;
243
+ case '4': await runTest(testMouseClick); break;
244
+ case '5': await runTest(testScroll); break;
245
+ case '6': await runTest(testKeyTap); break;
246
+ case '7': await runTest(testCombo); break;
247
+ case '8': await runTest(testTypeString); break;
248
+ case '9': await runTest(manualCommand); break;
249
+ case 'r':
250
+ case 'R':
251
+ controller.disconnect();
252
+ try {
253
+ controller.connect();
254
+ } catch (e) {
255
+ console.log('[X]', e.message);
256
+ }
257
+ break;
258
+ case 'b':
259
+ case 'B':
260
+ testBootloader();
261
+ break;
262
+ case '0':
263
+ case 'q':
264
+ console.log('\nBye!');
265
+ controller.disconnect();
266
+ process.exit(0);
267
+ default:
268
+ console.log('[?] Unknown command');
269
+ }
270
+
271
+ readline.question('\n[Press Enter]');
272
+ }
273
+ }
274
+
275
+ main().catch(e => {
276
+ console.error('Fatal error:', e);
277
+ process.exit(1);
278
+ });
279
+
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "macromate-hid",
3
+ "version": "1.0.0-beta.1",
4
+ "description": "Library for communicating with MacroMate HID device",
5
+ "main": "src/index.js",
6
+ "types": "types/index.d.ts",
7
+ "bin": {
8
+ "macromate": "./cli.js"
9
+ },
10
+ "scripts": {
11
+ "cli": "node cli.js",
12
+ "test": "echo \"Error: no test specified\" && exit 1"
13
+ },
14
+ "keywords": [
15
+ "hid",
16
+ "usb",
17
+ "macro",
18
+ "keyboard",
19
+ "mouse",
20
+ "automation",
21
+ "pico",
22
+ "rp2040"
23
+ ],
24
+ "author": "",
25
+ "license": "MIT",
26
+ "dependencies": {
27
+ "node-hid": "^3.2.0",
28
+ "readline-sync": "^1.4.10"
29
+ },
30
+ "engines": {
31
+ "node": ">=14.0.0"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": ""
36
+ },
37
+ "files": [
38
+ "src/",
39
+ "types/",
40
+ "cli.js",
41
+ "README.md"
42
+ ]
43
+ }
44
+