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 +310 -0
- package/cli.js +279 -0
- package/package.json +44 -0
- package/src/constants.js +106 -0
- package/src/controller.js +387 -0
- package/src/index.js +30 -0
- package/types/index.d.ts +338 -0
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
|
+
|