node-mac-recorder 2.16.24 โ 2.16.26
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/settings.local.json +1 -1
- package/package.json +1 -1
- package/src/mac_recorder.mm +11 -37
- package/src/screen_capture_kit.mm +6 -9
- package/src/window_selector.mm +11 -9
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"permissions": {
|
|
3
3
|
"allow": [
|
|
4
|
-
"Bash(FORCE_AVFOUNDATION=1 node -
|
|
4
|
+
"Bash(FORCE_AVFOUNDATION=1 node test-sequential.js)"
|
|
5
5
|
],
|
|
6
6
|
"deny": [],
|
|
7
7
|
"ask": []
|
package/package.json
CHANGED
package/src/mac_recorder.mm
CHANGED
|
@@ -567,50 +567,24 @@ Napi::Value GetDisplays(const Napi::CallbackInfo& info) {
|
|
|
567
567
|
Napi::Env env = info.Env();
|
|
568
568
|
|
|
569
569
|
@try {
|
|
570
|
-
// Get displays using
|
|
571
|
-
NSArray *screens = [NSScreen screens];
|
|
570
|
+
// Get active displays directly using CGDirectDisplayID
|
|
572
571
|
NSMutableArray *displays = [NSMutableArray array];
|
|
573
|
-
|
|
574
|
-
// Get real CGDirectDisplayIDs first
|
|
575
572
|
CGDirectDisplayID activeDisplays[32];
|
|
576
573
|
uint32_t displayCount;
|
|
577
574
|
CGGetActiveDisplayList(32, activeDisplays, &displayCount);
|
|
578
575
|
|
|
579
|
-
for (
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
// Find matching CGDirectDisplayID
|
|
584
|
-
CGDirectDisplayID displayID = 0;
|
|
585
|
-
bool isPrimary = false;
|
|
586
|
-
|
|
587
|
-
for (uint32_t j = 0; j < displayCount; j++) {
|
|
588
|
-
CGDirectDisplayID candidateID = activeDisplays[j];
|
|
589
|
-
CGRect displayBounds = CGDisplayBounds(candidateID);
|
|
590
|
-
|
|
591
|
-
if (fabs(frame.origin.x - displayBounds.origin.x) < 1.0 &&
|
|
592
|
-
fabs(frame.origin.y - displayBounds.origin.y) < 1.0 &&
|
|
593
|
-
fabs(frame.size.width - displayBounds.size.width) < 1.0 &&
|
|
594
|
-
fabs(frame.size.height - displayBounds.size.height) < 1.0) {
|
|
595
|
-
displayID = candidateID;
|
|
596
|
-
isPrimary = (candidateID == CGMainDisplayID());
|
|
597
|
-
break;
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// Fallback if no match found
|
|
602
|
-
if (displayID == 0 && i < displayCount) {
|
|
603
|
-
displayID = activeDisplays[i];
|
|
604
|
-
isPrimary = (displayID == CGMainDisplayID());
|
|
605
|
-
}
|
|
576
|
+
for (uint32_t i = 0; i < displayCount; i++) {
|
|
577
|
+
CGDirectDisplayID displayID = activeDisplays[i];
|
|
578
|
+
CGRect displayBounds = CGDisplayBounds(displayID);
|
|
579
|
+
bool isPrimary = (displayID == CGMainDisplayID());
|
|
606
580
|
|
|
607
581
|
NSDictionary *displayInfo = @{
|
|
608
|
-
@"id": @(displayID), //
|
|
609
|
-
@"name": [NSString stringWithFormat:@"Display %
|
|
610
|
-
@"width": @((int)
|
|
611
|
-
@"height": @((int)
|
|
612
|
-
@"x": @((int)
|
|
613
|
-
@"y": @((int)
|
|
582
|
+
@"id": @(displayID), // Direct CGDirectDisplayID
|
|
583
|
+
@"name": [NSString stringWithFormat:@"Display %u", (unsigned int)(i + 1)],
|
|
584
|
+
@"width": @((int)displayBounds.size.width),
|
|
585
|
+
@"height": @((int)displayBounds.size.height),
|
|
586
|
+
@"x": @((int)displayBounds.origin.x),
|
|
587
|
+
@"y": @((int)displayBounds.origin.y),
|
|
614
588
|
@"isPrimary": @(isPrimary)
|
|
615
589
|
};
|
|
616
590
|
[displays addObject:displayInfo];
|
|
@@ -329,7 +329,6 @@ static NSString *g_outputPath = nil;
|
|
|
329
329
|
}
|
|
330
330
|
|
|
331
331
|
NSLog(@"๐ Stopping pure ScreenCaptureKit recording");
|
|
332
|
-
g_isCleaningUp = YES;
|
|
333
332
|
|
|
334
333
|
// Store stream reference to prevent it from being deallocated
|
|
335
334
|
SCStream *streamToStop = g_stream;
|
|
@@ -340,11 +339,12 @@ static NSString *g_outputPath = nil;
|
|
|
340
339
|
}
|
|
341
340
|
NSLog(@"โ
Pure stream stopped");
|
|
342
341
|
|
|
342
|
+
// Immediately reset recording state to allow new recordings
|
|
343
|
+
g_isRecording = NO;
|
|
344
|
+
|
|
343
345
|
// Finalize on main queue to prevent threading issues
|
|
344
346
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
345
|
-
|
|
346
|
-
[ScreenCaptureKitRecorder finalizeRecording];
|
|
347
|
-
}
|
|
347
|
+
[ScreenCaptureKitRecorder cleanupVideoWriter];
|
|
348
348
|
});
|
|
349
349
|
}];
|
|
350
350
|
}
|
|
@@ -360,13 +360,10 @@ static NSString *g_outputPath = nil;
|
|
|
360
360
|
|
|
361
361
|
+ (void)finalizeRecording {
|
|
362
362
|
@synchronized([ScreenCaptureKitRecorder class]) {
|
|
363
|
-
if (g_isCleaningUp && g_isRecording == NO) {
|
|
364
|
-
NSLog(@"โ ๏ธ Already finalizing, skipping duplicate call");
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
363
|
NSLog(@"๐ฌ Finalizing pure ScreenCaptureKit recording");
|
|
369
364
|
|
|
365
|
+
// Set cleanup flag now that we're actually cleaning up
|
|
366
|
+
g_isCleaningUp = YES;
|
|
370
367
|
g_isRecording = NO;
|
|
371
368
|
|
|
372
369
|
if (g_recordingOutput) {
|
package/src/window_selector.mm
CHANGED
|
@@ -2360,33 +2360,35 @@ Napi::Value GetSelectedWindowInfo(const Napi::CallbackInfo& info) {
|
|
|
2360
2360
|
windowScreen = mainScreen;
|
|
2361
2361
|
}
|
|
2362
2362
|
|
|
2363
|
-
//
|
|
2363
|
+
// Convert NSScreen to CGDirectDisplayID properly
|
|
2364
2364
|
NSRect screenFrame = [windowScreen frame];
|
|
2365
|
+
NSNumber *screenNumber = [windowScreen deviceDescription][@"NSScreenNumber"];
|
|
2365
2366
|
|
|
2366
|
-
// Find
|
|
2367
|
-
CGDirectDisplayID
|
|
2367
|
+
// Find the actual CGDirectDisplayID that matches this screen's frame
|
|
2368
|
+
CGDirectDisplayID displayID = 0;
|
|
2368
2369
|
CGDirectDisplayID activeDisplays[32];
|
|
2369
2370
|
uint32_t displayCount;
|
|
2370
2371
|
CGGetActiveDisplayList(32, activeDisplays, &displayCount);
|
|
2371
2372
|
|
|
2372
|
-
for (uint32_t
|
|
2373
|
-
CGDirectDisplayID candidateID = activeDisplays[
|
|
2373
|
+
for (uint32_t i = 0; i < displayCount; i++) {
|
|
2374
|
+
CGDirectDisplayID candidateID = activeDisplays[i];
|
|
2374
2375
|
CGRect displayBounds = CGDisplayBounds(candidateID);
|
|
2375
2376
|
|
|
2377
|
+
// Match by screen frame coordinates
|
|
2376
2378
|
if (fabs(screenFrame.origin.x - displayBounds.origin.x) < 1.0 &&
|
|
2377
2379
|
fabs(screenFrame.origin.y - displayBounds.origin.y) < 1.0 &&
|
|
2378
2380
|
fabs(screenFrame.size.width - displayBounds.size.width) < 1.0 &&
|
|
2379
2381
|
fabs(screenFrame.size.height - displayBounds.size.height) < 1.0) {
|
|
2380
|
-
|
|
2382
|
+
displayID = candidateID;
|
|
2381
2383
|
break;
|
|
2382
2384
|
}
|
|
2383
2385
|
}
|
|
2384
2386
|
|
|
2385
|
-
NSLog(@"๐ Window screen
|
|
2387
|
+
NSLog(@"๐ Window screen: Frame=(%.0f,%.0f,%.0fx%.0f) NSScreenNumber=%@ โ CGDirectDisplayID=%u",
|
|
2386
2388
|
screenFrame.origin.x, screenFrame.origin.y,
|
|
2387
|
-
screenFrame.size.width, screenFrame.size.height,
|
|
2389
|
+
screenFrame.size.width, screenFrame.size.height, screenNumber, displayID);
|
|
2388
2390
|
|
|
2389
|
-
result.Set("screenId", Napi::Number::New(env,
|
|
2391
|
+
result.Set("screenId", Napi::Number::New(env, displayID));
|
|
2390
2392
|
result.Set("screenX", Napi::Number::New(env, (int)screenFrame.origin.x));
|
|
2391
2393
|
result.Set("screenY", Napi::Number::New(env, (int)screenFrame.origin.y));
|
|
2392
2394
|
result.Set("screenWidth", Napi::Number::New(env, (int)screenFrame.size.width));
|