node-mac-recorder 2.17.19 → 2.17.21

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.
Files changed (41) hide show
  1. package/.claude/settings.local.json +3 -1
  2. package/index.js +21 -200
  3. package/package.json +1 -1
  4. package/publish.sh +18 -0
  5. package/src/cursor_tracker.mm +37 -20
  6. package/cursor-data-1751364226346.json +0 -1
  7. package/cursor-data-1751364314136.json +0 -1
  8. package/cursor-data.json +0 -1
  9. package/cursor-debug-test.js +0 -60
  10. package/cursor-dpr-test.js +0 -73
  11. package/cursor-dpr-test.json +0 -1
  12. package/cursor-macbook-test.js +0 -63
  13. package/cursor-permission-test.js +0 -46
  14. package/cursor-scaling-debug.js +0 -53
  15. package/cursor-simple-test.js +0 -26
  16. package/debug-audio.js +0 -79
  17. package/debug-coordinates.js +0 -69
  18. package/debug-cursor-output.json +0 -1
  19. package/debug-macos14.js +0 -110
  20. package/debug-primary-window.js +0 -84
  21. package/debug-screen-selection.js +0 -81
  22. package/debug-window-selector.js +0 -178
  23. package/examples/electron-integration-example.js +0 -230
  24. package/examples/electron-preload.js +0 -46
  25. package/examples/electron-renderer.html +0 -634
  26. package/examples/integration-example.js +0 -228
  27. package/examples/window-selector-example.js +0 -254
  28. package/quick-cursor-test.json +0 -1
  29. package/test-both-cursor.json +0 -1
  30. package/test-cursor-fix.js +0 -105
  31. package/test-cursor-types.js +0 -117
  32. package/test-display-coordinates.js +0 -72
  33. package/test-integrated-recording.js +0 -120
  34. package/test-menubar-offset.js +0 -110
  35. package/test-output/primary-fix-test-1758266910543.json +0 -1
  36. package/test-output/unified-cursor-1758313640878.json +0 -1
  37. package/test-output/unified-cursor-1758313689471.json +0 -1
  38. package/test-primary-cursor.js +0 -154
  39. package/test-primary-fix.js +0 -120
  40. package/test-unified-cursor.js +0 -75
  41. package/test-window-recording.js +0 -149
@@ -1,228 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Window Selector + MacRecorder Integration Example
5
- * Bu örnek, window selector ile seçilen pencereyi doğrudan kaydetmeyi gösterir
6
- */
7
-
8
- const MacRecorder = require('../index');
9
- const path = require('path');
10
- const fs = require('fs');
11
-
12
- async function recordSelectedWindow() {
13
- console.log('🎥 Window Selection + Recording Integration');
14
- console.log('==========================================\n');
15
-
16
- const recorder = new MacRecorder();
17
- const selector = new MacRecorder.WindowSelector();
18
-
19
- try {
20
- // 1. İzinleri kontrol et
21
- console.log('1️⃣ Checking permissions...');
22
- const permissions = await recorder.checkPermissions();
23
- console.log('Permissions:', permissions);
24
-
25
- if (!permissions.screenRecording) {
26
- console.warn('⚠️ Screen recording permission required!');
27
- return;
28
- }
29
-
30
- // 2. Pencere seç
31
- console.log('\n2️⃣ Select a window to record...');
32
- console.log('Move cursor over windows and click "Select Window" button\n');
33
-
34
- const selectedWindow = await selector.selectWindow();
35
-
36
- console.log('✅ Selected window:', {
37
- title: selectedWindow.title,
38
- app: selectedWindow.appName,
39
- size: `${selectedWindow.width}x${selectedWindow.height}`,
40
- position: `(${selectedWindow.x}, ${selectedWindow.y})`
41
- });
42
-
43
- // 3. Çıktı dosyası hazırla
44
- const outputDir = path.join(__dirname, '..', 'recordings');
45
- if (!fs.existsSync(outputDir)) {
46
- fs.mkdirSync(outputDir, { recursive: true });
47
- }
48
-
49
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
50
- const fileName = `${selectedWindow.appName}-${selectedWindow.title}-${timestamp}.mov`
51
- .replace(/[^\w\-_.]/g, '_')
52
- .substring(0, 100);
53
- const outputPath = path.join(outputDir, fileName);
54
-
55
- // 4. Kayıt ayarları
56
- const recordingOptions = {
57
- windowId: selectedWindow.id,
58
- captureCursor: true,
59
- includeMicrophone: false,
60
- includeSystemAudio: true,
61
- captureArea: {
62
- x: selectedWindow.x - selectedWindow.screenX,
63
- y: selectedWindow.y - selectedWindow.screenY,
64
- width: selectedWindow.width,
65
- height: selectedWindow.height
66
- }
67
- };
68
-
69
- console.log('\n3️⃣ Starting recording...');
70
- console.log(`Output: ${outputPath}`);
71
- console.log('Recording options:', recordingOptions);
72
-
73
- // 5. Kayıt başlat
74
- await recorder.startRecording(outputPath, recordingOptions);
75
-
76
- console.log('\n🔴 Recording started!');
77
- console.log('Recording will stop automatically after 10 seconds...');
78
- console.log('Or press Ctrl+C to stop manually\n');
79
-
80
- // Progress tracking
81
- let secondsRecorded = 0;
82
- const progressInterval = setInterval(() => {
83
- secondsRecorded++;
84
- process.stdout.write(`\r⏱️ Recording: ${secondsRecorded}s / 10s`);
85
- }, 1000);
86
-
87
- // Ctrl+C handler
88
- let recordingStopped = false;
89
- process.on('SIGINT', async () => {
90
- if (!recordingStopped) {
91
- recordingStopped = true;
92
- clearInterval(progressInterval);
93
- console.log('\n\n🛑 Stopping recording...');
94
- await recorder.stopRecording();
95
- console.log(`✅ Recording saved: ${outputPath}`);
96
- process.exit(0);
97
- }
98
- });
99
-
100
- // 6. 10 saniye sonra durdur
101
- setTimeout(async () => {
102
- if (!recordingStopped) {
103
- recordingStopped = true;
104
- clearInterval(progressInterval);
105
- console.log('\n\n⏹️ Auto-stopping recording...');
106
- await recorder.stopRecording();
107
-
108
- // Dosya oluşup oluşmadığını kontrol et
109
- setTimeout(() => {
110
- if (fs.existsSync(outputPath)) {
111
- const stats = fs.statSync(outputPath);
112
- console.log(`✅ Recording completed successfully!`);
113
- console.log(`📁 File: ${outputPath}`);
114
- console.log(`📊 Size: ${(stats.size / 1024 / 1024).toFixed(2)} MB`);
115
- console.log('\n🎬 You can now play the video file!');
116
- } else {
117
- console.log('⚠️ Recording file not found. Check permissions and try again.');
118
- }
119
- process.exit(0);
120
- }, 2000);
121
- }
122
- }, 10000);
123
-
124
- } catch (error) {
125
- console.error('\n❌ Error:', error.message);
126
- console.error(error.stack);
127
- } finally {
128
- await selector.cleanup();
129
- }
130
- }
131
-
132
- async function selectAndAnalyze() {
133
- console.log('📊 Window Selection + Analysis Example');
134
- console.log('======================================\n');
135
-
136
- const selector = new MacRecorder.WindowSelector();
137
-
138
- try {
139
- console.log('Select a window to analyze...\n');
140
- const window = await selector.selectWindow();
141
-
142
- console.log('\n🔍 Window Analysis Report');
143
- console.log('=========================');
144
-
145
- // Basic info
146
- console.log(`📱 Application: ${window.appName}`);
147
- console.log(`🏷️ Title: "${window.title}"`);
148
- console.log(`🆔 Window ID: ${window.id}`);
149
-
150
- // Dimensions
151
- console.log(`\n📐 Dimensions:`);
152
- console.log(` Size: ${window.width} x ${window.height}`);
153
- console.log(` Area: ${(window.width * window.height).toLocaleString()} pixels`);
154
- console.log(` Aspect Ratio: ${(window.width / window.height).toFixed(2)}`);
155
-
156
- // Position
157
- console.log(`\n📍 Position:`);
158
- console.log(` Global: (${window.x}, ${window.y})`);
159
- console.log(` Screen: ${window.screenId} at (${window.screenX}, ${window.screenY})`);
160
- console.log(` Relative: (${window.x - window.screenX}, ${window.y - window.screenY})`);
161
-
162
- // Screen info
163
- console.log(`\n🖥️ Screen:`);
164
- console.log(` Size: ${window.screenWidth} x ${window.screenHeight}`);
165
- console.log(` Coverage: ${((window.width * window.height) / (window.screenWidth * window.screenHeight) * 100).toFixed(1)}%`);
166
-
167
- // Recording recommendation
168
- console.log(`\n🎥 Recording Recommendations:`);
169
- const area = window.width * window.height;
170
- if (area > 2000000) { // > 2M pixels
171
- console.log(' 📺 Large window - Good for detailed content recording');
172
- } else if (area > 500000) { // > 500K pixels
173
- console.log(' 📄 Medium window - Standard recording quality');
174
- } else {
175
- console.log(' 📝 Small window - Consider increasing size for better quality');
176
- }
177
-
178
- const aspectRatio = window.width / window.height;
179
- if (Math.abs(aspectRatio - 16/9) < 0.1) {
180
- console.log(' 🎬 16:9 aspect ratio - Perfect for video content');
181
- } else if (Math.abs(aspectRatio - 4/3) < 0.1) {
182
- console.log(' 📺 4:3 aspect ratio - Classic format');
183
- } else if (aspectRatio > 2) {
184
- console.log(' 📱 Wide aspect ratio - Good for dashboard/IDE content');
185
- } else {
186
- console.log(' 📄 Custom aspect ratio');
187
- }
188
-
189
- console.log(`\n✨ Analysis complete!`);
190
-
191
- } catch (error) {
192
- console.error('❌ Analysis failed:', error.message);
193
- } finally {
194
- await selector.cleanup();
195
- }
196
- }
197
-
198
- // Main function
199
- async function main() {
200
- const args = process.argv.slice(2);
201
-
202
- if (args.includes('--help')) {
203
- console.log('Integration Examples:');
204
- console.log('====================');
205
- console.log('node examples/integration-example.js [option]');
206
- console.log('');
207
- console.log('Options:');
208
- console.log(' --record Select and record a window (default)');
209
- console.log(' --analyze Select and analyze a window');
210
- console.log(' --help Show this help');
211
- return;
212
- }
213
-
214
- if (args.includes('--analyze')) {
215
- await selectAndAnalyze();
216
- } else {
217
- await recordSelectedWindow();
218
- }
219
- }
220
-
221
- if (require.main === module) {
222
- main().catch(console.error);
223
- }
224
-
225
- module.exports = {
226
- recordSelectedWindow,
227
- selectAndAnalyze
228
- };
@@ -1,254 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const WindowSelector = require('../window-selector');
4
-
5
- async function simpleExample() {
6
- console.log('🔍 Simple Window Selection Example');
7
- console.log('===================================\n');
8
-
9
- const selector = new WindowSelector();
10
-
11
- try {
12
- // Basit pencere seçimi
13
- console.log('Click on any window to select it...\n');
14
- const selectedWindow = await selector.selectWindow();
15
-
16
- console.log('Selected window:', {
17
- title: selectedWindow.title,
18
- app: selectedWindow.appName,
19
- position: `(${selectedWindow.x}, ${selectedWindow.y})`,
20
- size: `${selectedWindow.width}x${selectedWindow.height}`
21
- });
22
-
23
- return selectedWindow;
24
-
25
- } catch (error) {
26
- console.error('Error:', error.message);
27
- throw error;
28
- } finally {
29
- await selector.cleanup();
30
- }
31
- }
32
-
33
- async function advancedExample() {
34
- console.log('🎯 Advanced Window Selection with Events');
35
- console.log('=========================================\n');
36
-
37
- const selector = new WindowSelector();
38
-
39
- return new Promise(async (resolve, reject) => {
40
- try {
41
- // Event listener'ları ayarla
42
- selector.on('windowEntered', (window) => {
43
- console.log(`🏠 Hovering over: "${window.title}" (${window.appName})`);
44
- });
45
-
46
- selector.on('windowLeft', (window) => {
47
- console.log(`🚪 Left: "${window.title}"`);
48
- });
49
-
50
- selector.on('windowSelected', (window) => {
51
- console.log(`\n✅ Selected: "${window.title}" from ${window.appName}`);
52
- console.log(`📍 Position: (${window.x}, ${window.y})`);
53
- console.log(`📏 Size: ${window.width} x ${window.height}`);
54
- console.log(`🖥️ Screen: ${window.screenId} at (${window.screenX}, ${window.screenY})`);
55
- resolve(window);
56
- });
57
-
58
- selector.on('error', (error) => {
59
- console.error('❌ Selection error:', error.message);
60
- reject(error);
61
- });
62
-
63
- // Cancel handler
64
- process.on('SIGINT', async () => {
65
- console.log('\n🛑 Cancelled by user');
66
- await selector.cleanup();
67
- process.exit(0);
68
- });
69
-
70
- console.log('Move cursor over windows to see them highlighted');
71
- console.log('Click "Select Window" to choose one');
72
- console.log('Press Ctrl+C to cancel\n');
73
-
74
- await selector.startSelection();
75
-
76
- } catch (error) {
77
- reject(error);
78
- }
79
- });
80
- }
81
-
82
- async function multipleSelectionExample() {
83
- console.log('🔄 Multiple Window Selection Example');
84
- console.log('=====================================\n');
85
-
86
- const selector = new WindowSelector();
87
- const selectedWindows = [];
88
-
89
- try {
90
- for (let i = 1; i <= 3; i++) {
91
- console.log(`\n🎯 Selection ${i}/3:`);
92
- console.log('Select a window...\n');
93
-
94
- const window = await selector.selectWindow();
95
- selectedWindows.push({
96
- selection: i,
97
- title: window.title,
98
- app: window.appName,
99
- position: { x: window.x, y: window.y },
100
- size: { width: window.width, height: window.height },
101
- screen: window.screenId
102
- });
103
-
104
- console.log(`✅ Selection ${i} complete: "${window.title}"`);
105
- }
106
-
107
- console.log('\n📋 Summary of selected windows:');
108
- selectedWindows.forEach((win, index) => {
109
- console.log(`${index + 1}. "${win.title}" (${win.app}) - ${win.size.width}x${win.size.height}`);
110
- });
111
-
112
- return selectedWindows;
113
-
114
- } catch (error) {
115
- console.error('Error during multiple selection:', error.message);
116
- throw error;
117
- } finally {
118
- await selector.cleanup();
119
- }
120
- }
121
-
122
- async function windowAnalysisExample() {
123
- console.log('📊 Window Analysis Example');
124
- console.log('===========================\n');
125
-
126
- const selector = new WindowSelector();
127
-
128
- try {
129
- const window = await selector.selectWindow();
130
-
131
- console.log('🔍 Detailed Window Analysis:');
132
- console.log('============================');
133
-
134
- // Basic info
135
- console.log(`📱 Application: ${window.appName}`);
136
- console.log(`🏷️ Title: "${window.title}"`);
137
- console.log(`🆔 Window ID: ${window.id}`);
138
-
139
- // Position & Size
140
- console.log(`\n📍 Position & Dimensions:`);
141
- console.log(` Global position: (${window.x}, ${window.y})`);
142
- console.log(` Size: ${window.width} x ${window.height}`);
143
- console.log(` Area: ${window.width * window.height} pixels`);
144
- console.log(` Aspect ratio: ${(window.width / window.height).toFixed(2)}`);
145
-
146
- // Screen info
147
- console.log(`\n🖥️ Screen Information:`);
148
- console.log(` Screen ID: ${window.screenId}`);
149
- console.log(` Screen origin: (${window.screenX}, ${window.screenY})`);
150
- console.log(` Screen size: ${window.screenWidth} x ${window.screenHeight}`);
151
-
152
- // Relative position on screen
153
- const relativeX = window.x - window.screenX;
154
- const relativeY = window.y - window.screenY;
155
- console.log(` Relative position: (${relativeX}, ${relativeY})`);
156
-
157
- // Window positioning analysis
158
- console.log(`\n🎯 Position Analysis:`);
159
- const centerX = relativeX + window.width / 2;
160
- const centerY = relativeY + window.height / 2;
161
- const screenCenterX = window.screenWidth / 2;
162
- const screenCenterY = window.screenHeight / 2;
163
-
164
- console.log(` Window center: (${centerX.toFixed(0)}, ${centerY.toFixed(0)})`);
165
- console.log(` Screen center: (${screenCenterX.toFixed(0)}, ${screenCenterY.toFixed(0)})`);
166
-
167
- if (Math.abs(centerX - screenCenterX) < 50 && Math.abs(centerY - screenCenterY) < 50) {
168
- console.log(` 🎯 Window is centered on screen`);
169
- } else {
170
- const position = [];
171
- if (centerY < screenCenterY / 2) position.push('top');
172
- else if (centerY > screenCenterY * 1.5) position.push('bottom');
173
- else position.push('middle');
174
-
175
- if (centerX < screenCenterX / 2) position.push('left');
176
- else if (centerX > screenCenterX * 1.5) position.push('right');
177
- else position.push('center');
178
-
179
- console.log(` 📍 Window is positioned at ${position.join('-')} of screen`);
180
- }
181
-
182
- // Size classification
183
- console.log(`\n📏 Size Classification:`);
184
- const screenArea = window.screenWidth * window.screenHeight;
185
- const windowArea = window.width * window.height;
186
- const areaPercentage = (windowArea / screenArea) * 100;
187
-
188
- console.log(` Occupies ${areaPercentage.toFixed(1)}% of screen area`);
189
-
190
- if (areaPercentage > 75) {
191
- console.log(` 📺 Large window (> 75% of screen)`);
192
- } else if (areaPercentage > 25) {
193
- console.log(` 📄 Medium window (25-75% of screen)`);
194
- } else {
195
- console.log(` 📝 Small window (< 25% of screen)`);
196
- }
197
-
198
- return window;
199
-
200
- } catch (error) {
201
- console.error('Error during window analysis:', error.message);
202
- throw error;
203
- } finally {
204
- await selector.cleanup();
205
- }
206
- }
207
-
208
- // Main function to run examples
209
- async function main() {
210
- const args = process.argv.slice(2);
211
-
212
- if (args.includes('--help')) {
213
- console.log('Window Selector Examples:');
214
- console.log('========================');
215
- console.log('node examples/window-selector-example.js [option]');
216
- console.log('');
217
- console.log('Options:');
218
- console.log(' --simple Simple window selection (default)');
219
- console.log(' --advanced Advanced example with events');
220
- console.log(' --multiple Select multiple windows');
221
- console.log(' --analysis Detailed window analysis');
222
- console.log(' --help Show this help');
223
- return;
224
- }
225
-
226
- try {
227
- if (args.includes('--advanced')) {
228
- await advancedExample();
229
- } else if (args.includes('--multiple')) {
230
- await multipleSelectionExample();
231
- } else if (args.includes('--analysis')) {
232
- await windowAnalysisExample();
233
- } else {
234
- await simpleExample();
235
- }
236
-
237
- console.log('\n🎉 Example completed successfully!');
238
-
239
- } catch (error) {
240
- console.error('\n❌ Example failed:', error.message);
241
- process.exit(1);
242
- }
243
- }
244
-
245
- if (require.main === module) {
246
- main();
247
- }
248
-
249
- module.exports = {
250
- simpleExample,
251
- advancedExample,
252
- multipleSelectionExample,
253
- windowAnalysisExample
254
- };
@@ -1 +0,0 @@
1
- [{"x":798,"y":526,"timestamp":20,"unixTimeMs":1752410795804,"cursorType":"text","type":"move"}]
@@ -1 +0,0 @@
1
- [{"x":798,"y":526,"timestamp":21,"unixTimeMs":1752410827986,"cursorType":"text","type":"move"}]
@@ -1,105 +0,0 @@
1
- const MacRecorder = require('./index.js');
2
-
3
- async function testCursorCoordinates() {
4
- console.log('🧪 Testing cursor coordinate fixes for window recording...');
5
-
6
- const recorder = new MacRecorder();
7
-
8
- try {
9
- // Get available windows and displays
10
- const windows = await recorder.getWindows();
11
- const displays = await recorder.getDisplays();
12
-
13
- console.log('\n📱 Available displays:');
14
- displays.forEach((display, i) => {
15
- console.log(` ${i + 1}. Display ${display.id}: ${display.resolution} at (${display.x}, ${display.y}) ${display.isPrimary ? '(Primary)' : ''}`);
16
- });
17
-
18
- console.log('\n🪟 Available windows:');
19
- windows.slice(0, 5).forEach((window, i) => {
20
- console.log(` ${i + 1}. ${window.title} (${window.app}) - ${window.width}x${window.height} at (${window.x}, ${window.y})`);
21
- });
22
-
23
- if (windows.length === 0) {
24
- console.log('❌ No windows available for testing');
25
- return;
26
- }
27
-
28
- // Pick the first available window for testing
29
- const testWindow = windows[0];
30
- console.log(`\n🎯 Testing with window: ${testWindow.title}`);
31
- console.log(` Window position: (${testWindow.x}, ${testWindow.y})`);
32
- console.log(` Window size: ${testWindow.width}x${testWindow.height}`);
33
-
34
- // Check current cursor position before recording
35
- const cursorPos = recorder.getCursorPosition();
36
- console.log(`\n🖱️ Current cursor position (global): (${cursorPos.x}, ${cursorPos.y})`);
37
-
38
- // Setup recording options for window recording
39
- recorder.options.windowId = testWindow.id;
40
- recorder.options.captureCursor = true;
41
-
42
- console.log('\n🔧 Starting cursor capture test for window recording...');
43
-
44
- // Start cursor capture with window-relative coordinates
45
- const outputFile = `./test-output/cursor-test-window-${Date.now()}.json`;
46
-
47
- // Start cursor tracking first to see if coordinate transformation works
48
- await recorder.startCursorCapture(outputFile, {
49
- windowRelative: true,
50
- windowInfo: {
51
- x: testWindow.x,
52
- y: testWindow.y,
53
- width: testWindow.width,
54
- height: testWindow.height,
55
- displayId: null // Let it auto-detect
56
- }
57
- });
58
-
59
- console.log('✅ Cursor capture started successfully!');
60
- console.log('🖱️ Move your mouse around the window for 5 seconds...');
61
- console.log(` Window bounds: (0, 0) to (${testWindow.width}, ${testWindow.height})`);
62
-
63
- // Wait for 5 seconds to capture cursor movements
64
- await new Promise(resolve => setTimeout(resolve, 5000));
65
-
66
- console.log('\n🛑 Stopping cursor capture...');
67
- await recorder.stopCursorCapture();
68
-
69
- console.log(`✅ Test completed! Check cursor data in: ${outputFile}`);
70
-
71
- // Read and analyze some cursor data
72
- const fs = require('fs');
73
- if (fs.existsSync(outputFile)) {
74
- const cursorData = JSON.parse(fs.readFileSync(outputFile, 'utf8'));
75
- console.log(`\n📊 Captured ${cursorData.length} cursor events`);
76
-
77
- if (cursorData.length > 0) {
78
- const first = cursorData[0];
79
- const last = cursorData[cursorData.length - 1];
80
-
81
- console.log(` First event: (${first.x}, ${first.y}) - ${first.coordinateSystem}`);
82
- console.log(` Last event: (${last.x}, ${last.y}) - ${last.coordinateSystem}`);
83
-
84
- // Check if coordinates are within window bounds
85
- const inBounds = cursorData.filter(event =>
86
- event.x >= 0 && event.x < testWindow.width &&
87
- event.y >= 0 && event.y < testWindow.height
88
- );
89
-
90
- console.log(` Events within window bounds: ${inBounds.length}/${cursorData.length} (${Math.round(inBounds.length/cursorData.length*100)}%)`);
91
-
92
- if (inBounds.length > 0) {
93
- console.log('✅ Cursor coordinates appear to be correctly transformed to window-relative!');
94
- } else {
95
- console.log('❌ No cursor coordinates are within window bounds - transformation may be incorrect');
96
- }
97
- }
98
- }
99
-
100
- } catch (error) {
101
- console.error('❌ Test failed:', error.message);
102
- }
103
- }
104
-
105
- testCursorCoordinates().catch(console.error);