node-mac-recorder 2.16.26 → 2.16.28

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.
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "permissions": {
3
3
  "allow": [
4
- "Bash(FORCE_AVFOUNDATION=1 node test-sequential.js)"
4
+ "Bash(FORCE_AVFOUNDATION=1 node test-sequential.js)",
5
+ "Bash(grep:*)"
5
6
  ],
6
7
  "deny": [],
7
8
  "ask": []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.16.26",
3
+ "version": "2.16.28",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -114,8 +114,8 @@ Napi::Value StartRecordingElectronSafe(const Napi::CallbackInfo& info) {
114
114
  double width = areaObj.Get("width").As<Napi::Number>().DoubleValue();
115
115
  double height = areaObj.Get("height").As<Napi::Number>().DoubleValue();
116
116
 
117
- // Validate bounds
118
- if (width > 0 && height > 0 && x >= 0 && y >= 0) {
117
+ // Validate bounds - allow negative coordinates for external displays
118
+ if (width > 0 && height > 0) {
119
119
  mutableOptions[@"captureArea"] = @{
120
120
  @"x": @(x),
121
121
  @"y": @(y),
@@ -103,6 +103,7 @@ static NSString *g_outputPath = nil;
103
103
  SCContentFilter *filter = nil;
104
104
  NSInteger recordingWidth = 0;
105
105
  NSInteger recordingHeight = 0;
106
+ SCDisplay *targetDisplay = nil; // Move to shared scope
106
107
 
107
108
  // WINDOW RECORDING
108
109
  if (windowId && [windowId integerValue] != 0) {
@@ -130,7 +131,6 @@ static NSString *g_outputPath = nil;
130
131
  }
131
132
  // DISPLAY RECORDING
132
133
  else {
133
- SCDisplay *targetDisplay = nil;
134
134
 
135
135
  if (displayId && [displayId integerValue] != 0) {
136
136
  // Find specific display
@@ -187,17 +187,40 @@ static NSString *g_outputPath = nil;
187
187
  streamConfig.pixelFormat = kCVPixelFormatType_32BGRA;
188
188
  streamConfig.scalesToFit = NO;
189
189
 
190
- // Apply crop area using sourceRect
190
+ // Apply crop area using sourceRect - CONVERT GLOBAL TO DISPLAY-RELATIVE COORDINATES
191
191
  if (captureRect && captureRect[@"x"] && captureRect[@"y"] && captureRect[@"width"] && captureRect[@"height"]) {
192
- CGFloat cropX = [captureRect[@"x"] doubleValue];
193
- CGFloat cropY = [captureRect[@"y"] doubleValue];
192
+ CGFloat globalX = [captureRect[@"x"] doubleValue];
193
+ CGFloat globalY = [captureRect[@"y"] doubleValue];
194
194
  CGFloat cropWidth = [captureRect[@"width"] doubleValue];
195
195
  CGFloat cropHeight = [captureRect[@"height"] doubleValue];
196
196
 
197
- if (cropWidth > 0 && cropHeight > 0) {
198
- CGRect sourceRect = CGRectMake(cropX, cropY, cropWidth, cropHeight);
199
- streamConfig.sourceRect = sourceRect;
200
- NSLog(@"✂️ Crop sourceRect applied: (%.0f,%.0f) %.0fx%.0f", cropX, cropY, cropWidth, cropHeight);
197
+ if (cropWidth > 0 && cropHeight > 0 && targetDisplay) {
198
+ // Convert global coordinates to display-relative coordinates
199
+ CGRect displayBounds = targetDisplay.frame;
200
+ CGFloat displayRelativeX = globalX - displayBounds.origin.x;
201
+ CGFloat displayRelativeY = globalY - displayBounds.origin.y;
202
+
203
+ NSLog(@"🌐 Global coords: (%.0f,%.0f) on Display ID=%u", globalX, globalY, targetDisplay.displayID);
204
+ NSLog(@"🖥️ Display bounds: (%.0f,%.0f,%.0fx%.0f)",
205
+ displayBounds.origin.x, displayBounds.origin.y,
206
+ displayBounds.size.width, displayBounds.size.height);
207
+ NSLog(@"📍 Display-relative: (%.0f,%.0f) -> SourceRect", displayRelativeX, displayRelativeY);
208
+
209
+ // Validate coordinates are within display bounds
210
+ if (displayRelativeX >= 0 && displayRelativeY >= 0 &&
211
+ displayRelativeX + cropWidth <= displayBounds.size.width &&
212
+ displayRelativeY + cropHeight <= displayBounds.size.height) {
213
+
214
+ CGRect sourceRect = CGRectMake(displayRelativeX, displayRelativeY, cropWidth, cropHeight);
215
+ streamConfig.sourceRect = sourceRect;
216
+ NSLog(@"✂️ Crop sourceRect applied: (%.0f,%.0f) %.0fx%.0f (display-relative)",
217
+ displayRelativeX, displayRelativeY, cropWidth, cropHeight);
218
+ } else {
219
+ NSLog(@"❌ Crop coordinates out of display bounds - skipping crop");
220
+ NSLog(@" Relative: (%.0f,%.0f) size:(%.0fx%.0f) vs display:(%.0fx%.0f)",
221
+ displayRelativeX, displayRelativeY, cropWidth, cropHeight,
222
+ displayBounds.size.width, displayBounds.size.height);
223
+ }
201
224
  }
202
225
  }
203
226
 
@@ -475,8 +475,45 @@ void updateScreenOverlays();
475
475
  NSLog(@"🔥 Current window under cursor: %@", g_currentWindowUnderCursor);
476
476
 
477
477
  if (g_currentWindowUnderCursor) {
478
- g_selectedWindowInfo = [g_currentWindowUnderCursor retain];
479
- NSLog(@"🔥 Selected window info set: %@", g_selectedWindowInfo);
478
+ // Get window's screen information for display ID
479
+ NSMutableDictionary *windowInfoWithDisplay = [g_currentWindowUnderCursor mutableCopy];
480
+
481
+ // Get window bounds to determine which screen it's on
482
+ NSNumber *windowX = [g_currentWindowUnderCursor objectForKey:@"x"];
483
+ NSNumber *windowY = [g_currentWindowUnderCursor objectForKey:@"y"];
484
+
485
+ if (windowX && windowY) {
486
+ CGFloat x = [windowX doubleValue];
487
+ CGFloat y = [windowY doubleValue];
488
+
489
+ // Find the display that contains this window
490
+ CGDirectDisplayID activeDisplays[32];
491
+ uint32_t displayCount;
492
+ CGGetActiveDisplayList(32, activeDisplays, &displayCount);
493
+
494
+ CGDirectDisplayID targetDisplayID = 0;
495
+ for (uint32_t i = 0; i < displayCount; i++) {
496
+ CGDirectDisplayID displayID = activeDisplays[i];
497
+ CGRect displayBounds = CGDisplayBounds(displayID);
498
+
499
+ // Check if window center is within this display
500
+ if (x >= displayBounds.origin.x && x < displayBounds.origin.x + displayBounds.size.width &&
501
+ y >= displayBounds.origin.y && y < displayBounds.origin.y + displayBounds.size.height) {
502
+ targetDisplayID = displayID;
503
+ break;
504
+ }
505
+ }
506
+
507
+ if (targetDisplayID != 0) {
508
+ [windowInfoWithDisplay setObject:@(targetDisplayID) forKey:@"screenId"];
509
+ NSLog(@"🎯 Window on display ID: %u", targetDisplayID);
510
+ } else {
511
+ NSLog(@"⚠️ Could not determine display ID for window");
512
+ }
513
+ }
514
+
515
+ g_selectedWindowInfo = [windowInfoWithDisplay retain];
516
+ NSLog(@"🔥 Selected window info with display ID: %@", g_selectedWindowInfo);
480
517
  cleanupWindowSelector();
481
518
  } else {
482
519
  NSLog(@"⚠️ No window under cursor when button clicked!");