node-mac-recorder 1.14.1 → 1.14.2
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/CLAUDE.md +26 -2
- package/index.js +63 -14
- package/package.json +1 -1
- package/overlay-test.js +0 -84
package/CLAUDE.md
CHANGED
|
@@ -73,10 +73,22 @@ The package handles complex multi-display coordinate transformations:
|
|
|
73
73
|
- `checkPermissions()` - Verify macOS recording permissions
|
|
74
74
|
|
|
75
75
|
### Cursor Tracking
|
|
76
|
-
- `startCursorCapture(filepath)` - Begin real-time cursor tracking to JSON
|
|
76
|
+
- `startCursorCapture(filepath, options)` - Begin real-time cursor tracking to JSON
|
|
77
|
+
- `options.windowInfo` - Window information for window-relative coordinates
|
|
78
|
+
- `options.windowRelative` - Set to true for window-relative coordinates
|
|
77
79
|
- `stopCursorCapture()` - Stop tracking and close output file
|
|
78
80
|
- `getCursorPosition()` - Get current cursor position and state
|
|
79
81
|
|
|
82
|
+
### Events
|
|
83
|
+
The MacRecorder class emits the following events:
|
|
84
|
+
- `recordingStarted` - Emitted immediately when recording starts with recording details
|
|
85
|
+
- `started` - Emitted when recording is confirmed started (legacy event)
|
|
86
|
+
- `stopped` - Emitted when recording stops
|
|
87
|
+
- `completed` - Emitted when recording file is finalized
|
|
88
|
+
- `timeUpdate` - Emitted every second with elapsed time
|
|
89
|
+
- `cursorCaptureStarted` - Emitted when cursor capture begins
|
|
90
|
+
- `cursorCaptureStopped` - Emitted when cursor capture ends
|
|
91
|
+
|
|
80
92
|
### Thumbnails
|
|
81
93
|
- `getWindowThumbnail(windowId, options)` - Capture window preview image
|
|
82
94
|
- `getDisplayThumbnail(displayId, options)` - Capture display preview image
|
|
@@ -90,9 +102,14 @@ The package handles complex multi-display coordinate transformations:
|
|
|
90
102
|
|
|
91
103
|
### Common Development Patterns
|
|
92
104
|
- All recording operations are Promise-based
|
|
93
|
-
- Event emission for recording state changes (`started`, `stopped`, `completed`)
|
|
105
|
+
- Event emission for recording state changes (`recordingStarted`, `started`, `stopped`, `completed`)
|
|
106
|
+
- `recordingStarted` event provides immediate notification with recording details
|
|
94
107
|
- Automatic permission checking before operations
|
|
95
108
|
- Error handling with descriptive messages for permission issues
|
|
109
|
+
- Cursor tracking supports multiple coordinate systems:
|
|
110
|
+
- Global coordinates (default)
|
|
111
|
+
- Display-relative coordinates (when recording)
|
|
112
|
+
- Window-relative coordinates (with windowInfo parameter)
|
|
96
113
|
|
|
97
114
|
### Platform Requirements
|
|
98
115
|
- macOS only (enforced in install.js)
|
|
@@ -102,6 +119,13 @@ The package handles complex multi-display coordinate transformations:
|
|
|
102
119
|
### File Outputs
|
|
103
120
|
- Video recordings: `.mov` format (H.264/AAC)
|
|
104
121
|
- Cursor data: JSON format with timestamped events
|
|
122
|
+
- `x`, `y`: Cursor coordinates (coordinate system dependent)
|
|
123
|
+
- `timestamp`: Time from capture start (ms)
|
|
124
|
+
- `unixTimeMs`: Unix timestamp
|
|
125
|
+
- `cursorType`: macOS cursor type
|
|
126
|
+
- `type`: Event type (move, click, etc.)
|
|
127
|
+
- `coordinateSystem`: "global", "display-relative", or "window-relative"
|
|
128
|
+
- `windowInfo`: Window metadata (when using window-relative coordinates)
|
|
105
129
|
- Thumbnails: Base64-encoded PNG data URIs
|
|
106
130
|
|
|
107
131
|
## Troubleshooting
|
package/index.js
CHANGED
|
@@ -302,6 +302,13 @@ class MacRecorder extends EventEmitter {
|
|
|
302
302
|
this.emit("timeUpdate", elapsed);
|
|
303
303
|
}, 1000);
|
|
304
304
|
|
|
305
|
+
// Kayıt tam başladığı anda event emit et
|
|
306
|
+
this.emit("recordingStarted", {
|
|
307
|
+
outputPath: this.outputPath,
|
|
308
|
+
timestamp: this.recordingStartTime,
|
|
309
|
+
options: this.options
|
|
310
|
+
});
|
|
311
|
+
|
|
305
312
|
this.emit("started", this.outputPath);
|
|
306
313
|
resolve(this.outputPath);
|
|
307
314
|
} else {
|
|
@@ -506,9 +513,12 @@ class MacRecorder extends EventEmitter {
|
|
|
506
513
|
/**
|
|
507
514
|
* Cursor capture başlatır - otomatik olarak dosyaya yazmaya başlar
|
|
508
515
|
* Recording başlatılmışsa otomatik olarak display-relative koordinatlar kullanır
|
|
509
|
-
* @param {string}
|
|
516
|
+
* @param {string|number} intervalOrFilepath - Cursor data JSON dosya yolu veya interval
|
|
517
|
+
* @param {Object} options - Cursor capture seçenekleri
|
|
518
|
+
* @param {Object} options.windowInfo - Pencere bilgileri (window-relative koordinatlar için)
|
|
519
|
+
* @param {boolean} options.windowRelative - Koordinatları pencereye göre relative yap
|
|
510
520
|
*/
|
|
511
|
-
async startCursorCapture(intervalOrFilepath = 100) {
|
|
521
|
+
async startCursorCapture(intervalOrFilepath = 100, options = {}) {
|
|
512
522
|
let filepath;
|
|
513
523
|
let interval = 20; // Default 50 FPS
|
|
514
524
|
|
|
@@ -528,8 +538,20 @@ class MacRecorder extends EventEmitter {
|
|
|
528
538
|
throw new Error("Cursor capture is already running");
|
|
529
539
|
}
|
|
530
540
|
|
|
531
|
-
//
|
|
532
|
-
if (
|
|
541
|
+
// Koordinat sistemi belirle: window-relative, display-relative veya global
|
|
542
|
+
if (options.windowRelative && options.windowInfo) {
|
|
543
|
+
// Window-relative koordinatlar için pencere bilgilerini kullan
|
|
544
|
+
this.cursorDisplayInfo = {
|
|
545
|
+
displayId: options.windowInfo.displayId || null,
|
|
546
|
+
x: options.windowInfo.x || 0,
|
|
547
|
+
y: options.windowInfo.y || 0,
|
|
548
|
+
width: options.windowInfo.width,
|
|
549
|
+
height: options.windowInfo.height,
|
|
550
|
+
windowRelative: true,
|
|
551
|
+
windowInfo: options.windowInfo
|
|
552
|
+
};
|
|
553
|
+
} else if (this.recordingDisplayInfo) {
|
|
554
|
+
// Recording başlatılmışsa o display'i kullan
|
|
533
555
|
this.cursorDisplayInfo = this.recordingDisplayInfo;
|
|
534
556
|
} else {
|
|
535
557
|
// Main display bilgisini al (her zaman relative koordinatlar için)
|
|
@@ -568,23 +590,42 @@ class MacRecorder extends EventEmitter {
|
|
|
568
590
|
const position = nativeBinding.getCursorPosition();
|
|
569
591
|
const timestamp = Date.now() - this.cursorCaptureStartTime;
|
|
570
592
|
|
|
571
|
-
// Global koordinatları
|
|
593
|
+
// Global koordinatları relative koordinatlara çevir
|
|
572
594
|
let x = position.x;
|
|
573
595
|
let y = position.y;
|
|
596
|
+
let coordinateSystem = "global";
|
|
574
597
|
|
|
575
598
|
if (this.cursorDisplayInfo) {
|
|
576
|
-
//
|
|
599
|
+
// Offset'leri çıkar (display veya window)
|
|
577
600
|
x = position.x - this.cursorDisplayInfo.x;
|
|
578
601
|
y = position.y - this.cursorDisplayInfo.y;
|
|
579
602
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
603
|
+
if (this.cursorDisplayInfo.windowRelative) {
|
|
604
|
+
// Window-relative koordinatlar
|
|
605
|
+
coordinateSystem = "window-relative";
|
|
606
|
+
|
|
607
|
+
// Window bounds kontrolü - cursor window dışındaysa kaydetme
|
|
608
|
+
if (
|
|
609
|
+
x < 0 ||
|
|
610
|
+
y < 0 ||
|
|
611
|
+
x >= this.cursorDisplayInfo.width ||
|
|
612
|
+
y >= this.cursorDisplayInfo.height
|
|
613
|
+
) {
|
|
614
|
+
return; // Bu frame'i skip et - cursor pencere dışında
|
|
615
|
+
}
|
|
616
|
+
} else {
|
|
617
|
+
// Display-relative koordinatlar
|
|
618
|
+
coordinateSystem = "display-relative";
|
|
619
|
+
|
|
620
|
+
// Display bounds kontrolü
|
|
621
|
+
if (
|
|
622
|
+
x < 0 ||
|
|
623
|
+
y < 0 ||
|
|
624
|
+
x >= this.cursorDisplayInfo.width ||
|
|
625
|
+
y >= this.cursorDisplayInfo.height
|
|
626
|
+
) {
|
|
627
|
+
return; // Bu frame'i skip et - cursor display dışında
|
|
628
|
+
}
|
|
588
629
|
}
|
|
589
630
|
}
|
|
590
631
|
|
|
@@ -595,6 +636,14 @@ class MacRecorder extends EventEmitter {
|
|
|
595
636
|
unixTimeMs: Date.now(),
|
|
596
637
|
cursorType: position.cursorType,
|
|
597
638
|
type: position.eventType || "move",
|
|
639
|
+
coordinateSystem: coordinateSystem,
|
|
640
|
+
...(this.cursorDisplayInfo?.windowRelative && {
|
|
641
|
+
windowInfo: {
|
|
642
|
+
width: this.cursorDisplayInfo.width,
|
|
643
|
+
height: this.cursorDisplayInfo.height,
|
|
644
|
+
originalWindow: this.cursorDisplayInfo.windowInfo
|
|
645
|
+
}
|
|
646
|
+
})
|
|
598
647
|
};
|
|
599
648
|
|
|
600
649
|
// Sadece eventType değiştiğinde veya pozisyon değiştiğinde kaydet
|
package/package.json
CHANGED
package/overlay-test.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
const MacRecorder = require('./index');
|
|
2
|
-
|
|
3
|
-
async function testOverlayImprovements() {
|
|
4
|
-
console.log('🎯 Testing Overlay Improvements\n');
|
|
5
|
-
|
|
6
|
-
const recorder = new MacRecorder();
|
|
7
|
-
const WindowSelector = MacRecorder.WindowSelector;
|
|
8
|
-
const selector = new WindowSelector();
|
|
9
|
-
|
|
10
|
-
try {
|
|
11
|
-
console.log('1️⃣ Testing Window Selection with custom buttons...');
|
|
12
|
-
console.log(' - Custom "Start Record" and "Cancel" buttons should appear');
|
|
13
|
-
console.log(' - ESC key should cancel selection');
|
|
14
|
-
console.log(' - Cancel button should cancel selection');
|
|
15
|
-
console.log(' - Starting window selection...\n');
|
|
16
|
-
|
|
17
|
-
// Start window selection (non-blocking)
|
|
18
|
-
await selector.startSelection();
|
|
19
|
-
|
|
20
|
-
console.log('✅ Window selection started. Move mouse over windows to see overlay.');
|
|
21
|
-
console.log(' - Press ESC to cancel');
|
|
22
|
-
console.log(' - Click Cancel button to cancel');
|
|
23
|
-
console.log(' - Click Start Record to select window\n');
|
|
24
|
-
|
|
25
|
-
// Wait for selection or timeout
|
|
26
|
-
const startTime = Date.now();
|
|
27
|
-
const timeout = 30000; // 30 seconds
|
|
28
|
-
|
|
29
|
-
while (selector.getStatus().isSelecting && (Date.now() - startTime) < timeout) {
|
|
30
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const selectedWindow = selector.getSelectedWindow();
|
|
34
|
-
|
|
35
|
-
if (selectedWindow) {
|
|
36
|
-
console.log('🎬 Window selected:', selectedWindow.appName, '-', selectedWindow.title);
|
|
37
|
-
console.log(' Size:', selectedWindow.width + 'x' + selectedWindow.height);
|
|
38
|
-
console.log(' Position: (' + selectedWindow.x + ', ' + selectedWindow.y + ')');
|
|
39
|
-
|
|
40
|
-
console.log('\n2️⃣ Testing Recording Preview Overlay...');
|
|
41
|
-
console.log(' - Should show darkened overlay with window area transparent');
|
|
42
|
-
|
|
43
|
-
await selector.showRecordingPreview(selectedWindow);
|
|
44
|
-
console.log('✅ Recording preview shown. Check if window area is highlighted.');
|
|
45
|
-
|
|
46
|
-
// Wait 3 seconds
|
|
47
|
-
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
48
|
-
|
|
49
|
-
await selector.hideRecordingPreview();
|
|
50
|
-
console.log('✅ Recording preview hidden.');
|
|
51
|
-
|
|
52
|
-
} else {
|
|
53
|
-
console.log('🚫 No window selected (cancelled or timeout)');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
console.log('\n3️⃣ Testing Screen Selection with custom buttons...');
|
|
57
|
-
console.log(' - Custom "Start Record" and "Cancel" buttons should appear on each screen');
|
|
58
|
-
console.log(' - ESC key should cancel selection');
|
|
59
|
-
console.log(' - Cancel button should cancel selection');
|
|
60
|
-
|
|
61
|
-
const selectedScreen = await selector.selectScreen().catch(err => {
|
|
62
|
-
console.log('🚫 Screen selection cancelled:', err.message);
|
|
63
|
-
return null;
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
if (selectedScreen) {
|
|
67
|
-
console.log('🖥️ Screen selected:', selectedScreen.name);
|
|
68
|
-
console.log(' Resolution:', selectedScreen.resolution);
|
|
69
|
-
console.log(' Position: (' + selectedScreen.x + ', ' + selectedScreen.y + ')');
|
|
70
|
-
} else {
|
|
71
|
-
console.log('🚫 No screen selected (cancelled or timeout)');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
console.log('\n🎉 Overlay improvements test completed!');
|
|
75
|
-
|
|
76
|
-
} catch (error) {
|
|
77
|
-
console.error('❌ Test failed:', error.message);
|
|
78
|
-
} finally {
|
|
79
|
-
await selector.cleanup();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Run test
|
|
84
|
-
testOverlayImprovements().catch(console.error);
|