node-mac-recorder 2.15.9 → 2.15.10

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.
@@ -0,0 +1,69 @@
1
+ const MacRecorder = require('./index');
2
+
3
+ async function debugCoordinates() {
4
+ const recorder = new MacRecorder();
5
+ const displays = await recorder.getDisplays();
6
+
7
+ console.log('šŸ–„ļø Display coordinates analysis:');
8
+ displays.forEach((display, index) => {
9
+ console.log(`Display ${index}: ${display.name}`);
10
+ console.log(` ID: ${display.id}`);
11
+ console.log(` Position: (${display.x}, ${display.y})`);
12
+ console.log(` Size: ${display.width}x${display.height}`);
13
+ console.log(` isPrimary: ${display.isPrimary}`);
14
+ console.log('');
15
+ });
16
+
17
+ // Calculate combined frame like we do in native code
18
+ let combinedFrame = { x: 0, y: 0, width: 0, height: 0 };
19
+ let first = true;
20
+
21
+ for (const display of displays) {
22
+ if (first) {
23
+ combinedFrame = {
24
+ x: display.x,
25
+ y: display.y,
26
+ width: display.width,
27
+ height: display.height
28
+ };
29
+ first = false;
30
+ } else {
31
+ const minX = Math.min(combinedFrame.x, display.x);
32
+ const minY = Math.min(combinedFrame.y, display.y);
33
+ const maxX = Math.max(combinedFrame.x + combinedFrame.width, display.x + display.width);
34
+ const maxY = Math.max(combinedFrame.y + combinedFrame.height, display.y + display.height);
35
+
36
+ combinedFrame = {
37
+ x: minX,
38
+ y: minY,
39
+ width: maxX - minX,
40
+ height: maxY - minY
41
+ };
42
+ }
43
+ }
44
+
45
+ console.log('šŸ“ Combined frame calculation:');
46
+ console.log(` Origin: (${combinedFrame.x}, ${combinedFrame.y})`);
47
+ console.log(` Size: ${combinedFrame.width}x${combinedFrame.height}`);
48
+ console.log('');
49
+
50
+ console.log('šŸ”„ Coordinate conversion examples:');
51
+ displays.forEach((display, index) => {
52
+ console.log(`Display ${index} (${display.name}):`);
53
+ const localOriginX = display.x - combinedFrame.x;
54
+ const localOriginY = display.y - combinedFrame.y;
55
+ console.log(` Global offset from combined: (${localOriginX}, ${localOriginY})`);
56
+
57
+ // Test window at display origin
58
+ const testWindowGlobalX = display.x + 100;
59
+ const testWindowGlobalY = display.y + 100;
60
+ const localWindowX = testWindowGlobalX - combinedFrame.x;
61
+ const localWindowY = testWindowGlobalY - combinedFrame.y;
62
+
63
+ console.log(` Test window at (${testWindowGlobalX}, ${testWindowGlobalY}) global`);
64
+ console.log(` -> Local coordinates: (${localWindowX}, ${localWindowY})`);
65
+ console.log('');
66
+ });
67
+ }
68
+
69
+ debugCoordinates();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.15.9",
3
+ "version": "2.15.10",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -451,13 +451,47 @@ Napi::Value GetDisplays(const Napi::CallbackInfo& info) {
451
451
  NSArray *screens = [NSScreen screens];
452
452
  NSMutableArray *displays = [NSMutableArray array];
453
453
 
454
+ // Get real CGDirectDisplayIDs first
455
+ CGDirectDisplayID activeDisplays[32];
456
+ uint32_t displayCount;
457
+ CGGetActiveDisplayList(32, activeDisplays, &displayCount);
458
+
454
459
  for (NSUInteger i = 0; i < [screens count]; i++) {
455
460
  NSScreen *screen = [screens objectAtIndex:i];
461
+ NSRect frame = [screen frame];
462
+
463
+ // Find matching CGDirectDisplayID
464
+ CGDirectDisplayID displayID = 0;
465
+ bool isPrimary = false;
466
+
467
+ for (uint32_t j = 0; j < displayCount; j++) {
468
+ CGDirectDisplayID candidateID = activeDisplays[j];
469
+ CGRect displayBounds = CGDisplayBounds(candidateID);
470
+
471
+ if (fabs(frame.origin.x - displayBounds.origin.x) < 1.0 &&
472
+ fabs(frame.origin.y - displayBounds.origin.y) < 1.0 &&
473
+ fabs(frame.size.width - displayBounds.size.width) < 1.0 &&
474
+ fabs(frame.size.height - displayBounds.size.height) < 1.0) {
475
+ displayID = candidateID;
476
+ isPrimary = (candidateID == CGMainDisplayID());
477
+ break;
478
+ }
479
+ }
480
+
481
+ // Fallback if no match found
482
+ if (displayID == 0 && i < displayCount) {
483
+ displayID = activeDisplays[i];
484
+ isPrimary = (displayID == CGMainDisplayID());
485
+ }
486
+
456
487
  NSDictionary *displayInfo = @{
457
- @"id": @(i + 1),
488
+ @"id": @(displayID), // Use real display ID
458
489
  @"name": [NSString stringWithFormat:@"Display %lu", (unsigned long)(i + 1)],
459
- @"width": @((int)screen.frame.size.width),
460
- @"height": @((int)screen.frame.size.height)
490
+ @"width": @((int)frame.size.width),
491
+ @"height": @((int)frame.size.height),
492
+ @"x": @((int)frame.origin.x),
493
+ @"y": @((int)frame.origin.y),
494
+ @"isPrimary": @(isPrimary)
461
495
  };
462
496
  [displays addObject:displayInfo];
463
497
  }
@@ -0,0 +1,88 @@
1
+ const MacRecorder = require('./index');
2
+ const WindowSelector = MacRecorder.WindowSelector;
3
+
4
+ async function testWindowSelector() {
5
+ console.log('🪟 Testing FIXED window selector multi-display...');
6
+
7
+ const recorder = new MacRecorder();
8
+ const displays = await recorder.getDisplays();
9
+
10
+ console.log('šŸ“Š Display setup:');
11
+ displays.forEach((display, index) => {
12
+ console.log(` ${display.name}: ${display.resolution} at (${display.x}, ${display.y}) ${display.isPrimary ? '[PRIMARY]' : ''}`);
13
+ });
14
+
15
+ const selector = new WindowSelector();
16
+
17
+ try {
18
+ console.log('\nšŸ” Starting window selection...');
19
+ console.log(' - Test windows on BOTH displays');
20
+ console.log(' - Check if buttons appear correctly positioned');
21
+ console.log(' - Primary display should now work correctly');
22
+
23
+ await selector.startSelection();
24
+
25
+ // Let it run for 20 seconds for thorough testing
26
+ await new Promise(resolve => setTimeout(resolve, 20000));
27
+
28
+ console.log('šŸ›‘ Stopping window selection...');
29
+ await selector.stopSelection();
30
+
31
+ console.log('āœ… Window selector test completed!');
32
+
33
+ } catch (error) {
34
+ console.log(`āŒ Window selector test failed: ${error.message}`);
35
+ console.log(error.stack);
36
+ }
37
+ }
38
+
39
+ async function testSecondaryDisplayRecording() {
40
+ console.log('\nšŸŽ„ Testing secondary display recording...');
41
+
42
+ const recorder = new MacRecorder();
43
+ const displays = await recorder.getDisplays();
44
+
45
+ const secondaryDisplay = displays.find(d => !d.isPrimary);
46
+ if (!secondaryDisplay) {
47
+ console.log('āš ļø No secondary display found');
48
+ return;
49
+ }
50
+
51
+ console.log(`šŸ–„ļø Testing recording on ${secondaryDisplay.name} (ID: ${secondaryDisplay.id})`);
52
+
53
+ try {
54
+ const outputPath = `./test-output/secondary-display-fix-test.mov`;
55
+
56
+ await recorder.startRecording(outputPath, {
57
+ displayId: secondaryDisplay.id,
58
+ captureCursor: true,
59
+ includeMicrophone: false,
60
+ includeSystemAudio: false
61
+ });
62
+
63
+ console.log('āœ… Recording started on secondary display');
64
+
65
+ // Record for 3 seconds
66
+ await new Promise(resolve => setTimeout(resolve, 3000));
67
+
68
+ await recorder.stopRecording();
69
+ console.log('āœ… Recording completed on secondary display');
70
+
71
+ } catch (error) {
72
+ console.log(`āŒ Secondary display recording failed: ${error.message}`);
73
+ }
74
+ }
75
+
76
+ async function runTests() {
77
+ try {
78
+ await testWindowSelector();
79
+ await testSecondaryDisplayRecording();
80
+
81
+ console.log('\nšŸŽ‰ All tests completed!');
82
+
83
+ } catch (error) {
84
+ console.log(`āŒ Test suite failed: ${error.message}`);
85
+ }
86
+ }
87
+
88
+ runTests();