node-mac-recorder 2.4.7 → 2.4.9

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/index.js CHANGED
@@ -950,6 +950,63 @@ class MacRecorder extends EventEmitter {
950
950
 
951
951
  return Promise.all(windowPromises);
952
952
  }
953
+
954
+ // Window Selection Methods (ScreenCaptureKit compatible)
955
+ startWindowSelection() {
956
+ if (!nativeBinding.startWindowSelection) {
957
+ throw new Error('Window selection is not available in this build');
958
+ }
959
+ return nativeBinding.startWindowSelection();
960
+ }
961
+
962
+ stopWindowSelection() {
963
+ if (!nativeBinding.stopWindowSelection) {
964
+ return false;
965
+ }
966
+ return nativeBinding.stopWindowSelection();
967
+ }
968
+
969
+ getSelectedWindowInfo() {
970
+ if (!nativeBinding.getSelectedWindowInfo) {
971
+ return null;
972
+ }
973
+ return nativeBinding.getSelectedWindowInfo();
974
+ }
975
+
976
+ getWindowSelectionStatus() {
977
+ if (!nativeBinding.getWindowSelectionStatus) {
978
+ return { isSelecting: false, hasSelectedWindow: false };
979
+ }
980
+ return nativeBinding.getWindowSelectionStatus();
981
+ }
982
+
983
+ bringWindowToFront(windowId) {
984
+ if (!nativeBinding.bringWindowToFront) {
985
+ return false;
986
+ }
987
+ return nativeBinding.bringWindowToFront(windowId);
988
+ }
989
+
990
+ setBringToFrontEnabled(enabled) {
991
+ if (!nativeBinding.setBringToFrontEnabled) {
992
+ return false;
993
+ }
994
+ return nativeBinding.setBringToFrontEnabled(enabled);
995
+ }
996
+
997
+ showRecordingPreview(windowInfo) {
998
+ if (!nativeBinding.showRecordingPreview) {
999
+ return false;
1000
+ }
1001
+ return nativeBinding.showRecordingPreview(windowInfo);
1002
+ }
1003
+
1004
+ hideRecordingPreview() {
1005
+ if (!nativeBinding.hideRecordingPreview) {
1006
+ return false;
1007
+ }
1008
+ return nativeBinding.hideRecordingPreview();
1009
+ }
953
1010
  }
954
1011
 
955
1012
  // WindowSelector modülünü de export edelim
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.4.7",
3
+ "version": "2.4.9",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -770,8 +770,33 @@ Napi::Value GetWindows(const Napi::CallbackInfo& info) {
770
770
  Napi::Object windowObj = Napi::Object::New(env);
771
771
  windowObj.Set("id", Napi::Number::New(env, window.windowID));
772
772
  windowObj.Set("title", Napi::String::New(env, window.title ? [window.title UTF8String] : ""));
773
- windowObj.Set("ownerName", Napi::String::New(env, window.owningApplication.applicationName ? [window.owningApplication.applicationName UTF8String] : ""));
774
- windowObj.Set("bounds", Napi::Object::New(env)); // TODO: Add bounds details
773
+
774
+ // Safely get application information (can be nil for some windows)
775
+ NSString *appName = @"";
776
+ NSString *bundleId = @"";
777
+ if (window.owningApplication) {
778
+ appName = window.owningApplication.applicationName ?: @"";
779
+ bundleId = window.owningApplication.bundleIdentifier ?: @"";
780
+ }
781
+
782
+ windowObj.Set("appName", Napi::String::New(env, [appName UTF8String]));
783
+ windowObj.Set("ownerName", Napi::String::New(env, [appName UTF8String]));
784
+ windowObj.Set("bundleId", Napi::String::New(env, [bundleId UTF8String]));
785
+
786
+ // Add frame details
787
+ CGRect frame = window.frame;
788
+ windowObj.Set("x", Napi::Number::New(env, (int)frame.origin.x));
789
+ windowObj.Set("y", Napi::Number::New(env, (int)frame.origin.y));
790
+ windowObj.Set("width", Napi::Number::New(env, (int)frame.size.width));
791
+ windowObj.Set("height", Napi::Number::New(env, (int)frame.size.height));
792
+
793
+ // Legacy bounds object for compatibility
794
+ Napi::Object boundsObj = Napi::Object::New(env);
795
+ boundsObj.Set("x", Napi::Number::New(env, (int)frame.origin.x));
796
+ boundsObj.Set("y", Napi::Number::New(env, (int)frame.origin.y));
797
+ boundsObj.Set("width", Napi::Number::New(env, (int)frame.size.width));
798
+ boundsObj.Set("height", Napi::Number::New(env, (int)frame.size.height));
799
+ windowObj.Set("bounds", boundsObj);
775
800
 
776
801
  windowsArray.Set(index++, windowObj);
777
802
  }
@@ -5,6 +5,7 @@
5
5
  #import <ApplicationServices/ApplicationServices.h>
6
6
  #import <Carbon/Carbon.h>
7
7
  #import <Accessibility/Accessibility.h>
8
+ #import <ScreenCaptureKit/ScreenCaptureKit.h>
8
9
 
9
10
  // Global state for window selection
10
11
  static bool g_isWindowSelecting = false;
@@ -35,6 +36,7 @@ void cleanupWindowSelector();
35
36
  void updateOverlay();
36
37
  NSDictionary* getWindowUnderCursor(CGPoint point);
37
38
  NSArray* getAllSelectableWindows();
39
+ NSArray* getAllSelectableWindowsLegacy();
38
40
  bool bringWindowToFront(int windowId);
39
41
  void cleanupRecordingPreview();
40
42
  bool showRecordingPreview(NSDictionary *windowInfo);
@@ -233,7 +235,7 @@ bool hideScreenRecordingPreview();
233
235
  NSInteger screenIndex = [button tag];
234
236
 
235
237
  // Get screen info from global array using button tag
236
- if (g_allScreens && screenIndex >= 0 && screenIndex < [g_allScreens count]) {
238
+ if (g_allScreens && screenIndex >= 0 && screenIndex < (NSInteger)[g_allScreens count]) {
237
239
  NSDictionary *screenInfo = [g_allScreens objectAtIndex:screenIndex];
238
240
  g_selectedScreenInfo = [screenInfo copy];
239
241
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
@@ -367,8 +369,83 @@ bool bringWindowToFront(int windowId) {
367
369
  }
368
370
  }
369
371
 
370
- // Get all selectable windows
372
+ // Get all selectable windows using ScreenCaptureKit
371
373
  NSArray* getAllSelectableWindows() {
374
+ @autoreleasepool {
375
+ NSMutableArray *windows = [NSMutableArray array];
376
+
377
+ // Check if ScreenCaptureKit is available (requires macOS 12.3+)
378
+ if (@available(macOS 12.3, *)) {
379
+ // Use dispatch_semaphore for synchronous SCShareableContent retrieval
380
+ dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
381
+ __block SCShareableContent *content = nil;
382
+ __block NSError *error = nil;
383
+
384
+ [SCShareableContent getShareableContentWithCompletionHandler:^(SCShareableContent *shareableContent, NSError *contentError) {
385
+ content = shareableContent;
386
+ error = contentError;
387
+ dispatch_semaphore_signal(semaphore);
388
+ }];
389
+
390
+ // Wait for completion (timeout after 5 seconds)
391
+ dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC);
392
+ if (dispatch_semaphore_wait(semaphore, timeout) == 0 && content) {
393
+ NSLog(@"✅ ScreenCaptureKit: Found %lu windows", (unsigned long)content.windows.count);
394
+
395
+ for (SCWindow *scWindow in content.windows) {
396
+ // Skip windows without proper frame or title
397
+ if (scWindow.frame.size.width < 50 || scWindow.frame.size.height < 50) continue;
398
+ if (!scWindow.owningApplication) continue;
399
+
400
+ // Skip system applications
401
+ NSString *bundleId = scWindow.owningApplication.bundleIdentifier;
402
+ NSString *appName = scWindow.owningApplication.applicationName;
403
+ if ([bundleId hasPrefix:@"com.apple.dock"] ||
404
+ [bundleId hasPrefix:@"com.apple.WindowServer"] ||
405
+ [bundleId hasPrefix:@"com.apple.controlcenter"] ||
406
+ [bundleId hasPrefix:@"com.apple.notificationcenterui"]) {
407
+ continue;
408
+ }
409
+
410
+ // Convert SCWindow coordinates to match CGWindow coordinate system
411
+ CGRect frame = scWindow.frame;
412
+ int x = (int)frame.origin.x;
413
+ int y = (int)frame.origin.y;
414
+ int width = (int)frame.size.width;
415
+ int height = (int)frame.size.height;
416
+
417
+ NSString *windowTitle = scWindow.title ?: @"Untitled";
418
+ if ([windowTitle length] == 0) windowTitle = @"Untitled";
419
+
420
+ NSDictionary *window = @{
421
+ @"id": @(scWindow.windowID),
422
+ @"title": windowTitle,
423
+ @"appName": appName ?: @"Unknown App",
424
+ @"x": @(x),
425
+ @"y": @(y),
426
+ @"width": @(width),
427
+ @"height": @(height),
428
+ @"bundleId": bundleId ?: @""
429
+ };
430
+
431
+ [windows addObject:window];
432
+ }
433
+ } else {
434
+ NSLog(@"❌ ScreenCaptureKit: Failed to get shareable content or timeout occurred");
435
+ // Fall back to CGWindowList as backup
436
+ return getAllSelectableWindowsLegacy();
437
+ }
438
+ } else {
439
+ NSLog(@"⚠️ ScreenCaptureKit not available, falling back to CGWindowList");
440
+ return getAllSelectableWindowsLegacy();
441
+ }
442
+
443
+ return [windows copy];
444
+ }
445
+ }
446
+
447
+ // Legacy window enumeration using CGWindowList (fallback for older macOS)
448
+ NSArray* getAllSelectableWindowsLegacy() {
372
449
  @autoreleasepool {
373
450
  NSMutableArray *windows = [NSMutableArray array];
374
451
 
@@ -734,7 +811,7 @@ bool startScreenSelection() {
734
811
  NSMutableArray *screenInfoArray = [[NSMutableArray alloc] init];
735
812
  g_screenOverlayWindows = [[NSMutableArray alloc] init];
736
813
 
737
- for (NSInteger i = 0; i < [screens count]; i++) {
814
+ for (NSUInteger i = 0; i < [screens count]; i++) {
738
815
  NSScreen *screen = [screens objectAtIndex:i];
739
816
  NSRect screenFrame = [screen frame];
740
817
 
@@ -922,10 +999,10 @@ bool showScreenRecordingPreview(NSDictionary *screenInfo) {
922
999
  NSArray *screens = [NSScreen screens];
923
1000
  if (!screens || [screens count] == 0) return false;
924
1001
 
925
- int selectedScreenId = [[screenInfo objectForKey:@"id"] intValue];
1002
+ NSUInteger selectedScreenId = (NSUInteger)[[screenInfo objectForKey:@"id"] intValue];
926
1003
 
927
1004
  // Create overlay for each screen except the selected one
928
- for (NSInteger i = 0; i < [screens count]; i++) {
1005
+ for (NSUInteger i = 0; i < [screens count]; i++) {
929
1006
  if (i == selectedScreenId) continue; // Skip selected screen
930
1007
 
931
1008
  NSScreen *screen = [screens objectAtIndex:i];
@@ -956,7 +1033,7 @@ bool showScreenRecordingPreview(NSDictionary *screenInfo) {
956
1033
  }
957
1034
  }
958
1035
 
959
- NSLog(@"🎬 SCREEN RECORDING PREVIEW: Showing overlay for Screen %d", selectedScreenId);
1036
+ NSLog(@"🎬 SCREEN RECORDING PREVIEW: Showing overlay for Screen %lu", (unsigned long)selectedScreenId);
960
1037
 
961
1038
  return true;
962
1039
 
@@ -974,6 +1051,42 @@ bool hideScreenRecordingPreview() {
974
1051
  Napi::Value StartWindowSelection(const Napi::CallbackInfo& info) {
975
1052
  Napi::Env env = info.Env();
976
1053
 
1054
+ // Electron safety check - prevent NSWindow crashes
1055
+ const char* electronVersion = getenv("ELECTRON_VERSION");
1056
+ const char* electronRunAs = getenv("ELECTRON_RUN_AS_NODE");
1057
+
1058
+ NSLog(@"🔍 Debug: electronVersion='%s', electronRunAs='%s'",
1059
+ electronVersion ? electronVersion : "null",
1060
+ electronRunAs ? electronRunAs : "null");
1061
+
1062
+ if (electronVersion || electronRunAs) {
1063
+ NSLog(@"🔍 Detected Electron environment - using safe mode");
1064
+
1065
+ // In Electron, return window list without creating native NSWindow overlays
1066
+ // The Electron app can handle UI selection itself
1067
+ @try {
1068
+ NSArray *windows = getAllSelectableWindows();
1069
+
1070
+ if (!windows || [windows count] == 0) {
1071
+ NSLog(@"❌ No selectable windows found");
1072
+ return Napi::Boolean::New(env, false);
1073
+ }
1074
+
1075
+ // Store windows for later retrieval via getWindowSelectionStatus
1076
+ g_allWindows = [getAllSelectableWindows() mutableCopy];
1077
+ g_isWindowSelecting = true;
1078
+
1079
+ // Return true to indicate windows are available
1080
+ // Electron app should call getWindowSelectionStatus to get the list
1081
+ NSLog(@"✅ Electron-safe mode: %lu windows available for selection", (unsigned long)[windows count]);
1082
+ return Napi::Boolean::New(env, true);
1083
+
1084
+ } @catch (NSException *exception) {
1085
+ NSLog(@"❌ Exception in Electron-safe window selection: %@", [exception reason]);
1086
+ return Napi::Boolean::New(env, false);
1087
+ }
1088
+ }
1089
+
977
1090
  if (g_isWindowSelecting) {
978
1091
  NSLog(@"⚠️ Window selection already in progress");
979
1092
  return Napi::Boolean::New(env, false);
@@ -981,7 +1094,7 @@ Napi::Value StartWindowSelection(const Napi::CallbackInfo& info) {
981
1094
 
982
1095
  @try {
983
1096
  // Get all windows
984
- g_allWindows = getAllSelectableWindows();
1097
+ g_allWindows = [getAllSelectableWindows() mutableCopy];
985
1098
 
986
1099
  if (!g_allWindows || [g_allWindows count] == 0) {
987
1100
  Napi::Error::New(env, "No selectable windows found").ThrowAsJavaScriptException();
@@ -1338,6 +1451,51 @@ Napi::Value HideRecordingPreview(const Napi::CallbackInfo& info) {
1338
1451
  Napi::Value StartScreenSelection(const Napi::CallbackInfo& info) {
1339
1452
  Napi::Env env = info.Env();
1340
1453
 
1454
+ // Electron safety check - prevent NSWindow crashes
1455
+ const char* electronVersion = getenv("ELECTRON_VERSION");
1456
+ const char* electronRunAs = getenv("ELECTRON_RUN_AS_NODE");
1457
+
1458
+ NSLog(@"🔍 Screen Debug: electronVersion='%s', electronRunAs='%s'",
1459
+ electronVersion ? electronVersion : "null",
1460
+ electronRunAs ? electronRunAs : "null");
1461
+
1462
+ if (electronVersion || electronRunAs) {
1463
+ NSLog(@"🔍 Detected Electron environment - using safe screen selection");
1464
+
1465
+ // In Electron, return screen list without creating native NSWindow overlays
1466
+ @try {
1467
+ NSArray *screens = [NSScreen screens];
1468
+
1469
+ if (!screens || [screens count] == 0) {
1470
+ NSLog(@"❌ No screens available");
1471
+ return Napi::Boolean::New(env, false);
1472
+ }
1473
+
1474
+ // Store screens and select first one automatically for Electron
1475
+ g_allScreens = screens;
1476
+ g_isScreenSelecting = true;
1477
+
1478
+ NSScreen *mainScreen = [screens firstObject];
1479
+ g_selectedScreenInfo = @{
1480
+ @"id": @((int)[screens indexOfObject:mainScreen]),
1481
+ @"width": @((int)mainScreen.frame.size.width),
1482
+ @"height": @((int)mainScreen.frame.size.height),
1483
+ @"x": @((int)mainScreen.frame.origin.x),
1484
+ @"y": @((int)mainScreen.frame.origin.y)
1485
+ };
1486
+
1487
+ // Mark as complete so getSelectedScreenInfo returns the selection
1488
+ g_isScreenSelecting = false;
1489
+
1490
+ NSLog(@"✅ Electron-safe screen selection: %lu screens available", (unsigned long)[screens count]);
1491
+ return Napi::Boolean::New(env, true);
1492
+
1493
+ } @catch (NSException *exception) {
1494
+ NSLog(@"❌ Exception in Electron-safe screen selection: %@", [exception reason]);
1495
+ return Napi::Boolean::New(env, false);
1496
+ }
1497
+ }
1498
+
1341
1499
  @try {
1342
1500
  bool success = startScreenSelection();
1343
1501
  return Napi::Boolean::New(env, success);
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+
3
+ const nativeBinding = require('./build/Release/mac_recorder.node');
4
+
5
+ console.log('Testing ScreenCaptureKit availability...');
6
+
7
+ // Test the native functions directly
8
+ try {
9
+ console.log('Native binding methods:', Object.keys(nativeBinding));
10
+
11
+ // Check if we have the getWindows method
12
+ if (nativeBinding.getWindows) {
13
+ console.log('✅ getWindows method available');
14
+ const windows = nativeBinding.getWindows();
15
+ console.log(`Found ${windows.length} windows`);
16
+
17
+ if (windows.length > 0) {
18
+ console.log('First window:', windows[0]);
19
+ }
20
+ } else {
21
+ console.log('❌ getWindows method not available');
22
+ }
23
+
24
+ } catch (error) {
25
+ console.error('Error:', error.message);
26
+ }
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+
3
+ const MacRecorder = require('./index.js');
4
+
5
+ async function testWindowSelector() {
6
+ try {
7
+ console.log('🧪 Testing ScreenCaptureKit-compatible window selector...');
8
+
9
+ // Create recorder instance
10
+ const recorder = new MacRecorder();
11
+
12
+ // Test if we can get windows
13
+ const windows = await recorder.getWindows();
14
+ console.log(`✅ Found ${windows.length} windows`);
15
+
16
+ if (windows.length > 0) {
17
+ console.log('🔍 Sample windows:');
18
+ windows.slice(0, 3).forEach((win, i) => {
19
+ console.log(` ${i+1}. ${win.appName || 'Unknown'} - "${win.title || 'Untitled'}" [${win.width || 0}x${win.height || 0}]`);
20
+ console.log(` ID: ${win.id}, Bundle: ${win.bundleId || 'N/A'}`);
21
+ });
22
+ }
23
+
24
+ console.log('🪟 Testing window selection overlay...');
25
+
26
+ // Test window selection (will use ScreenCaptureKit if available)
27
+ const started = recorder.startWindowSelection();
28
+ console.log('Window selection started:', started);
29
+
30
+ if (started) {
31
+ console.log('✅ Window selector started successfully with ScreenCaptureKit integration');
32
+ console.log('📝 Press ESC to cancel or interact with the overlay');
33
+
34
+ // Wait a bit then cleanup
35
+ setTimeout(() => {
36
+ recorder.stopWindowSelection();
37
+ console.log('🧹 Window selector stopped');
38
+
39
+ console.log('✅ Test completed successfully!');
40
+ console.log('🎉 ScreenCaptureKit integration is working properly');
41
+ process.exit(0);
42
+ }, 10000);
43
+ } else {
44
+ console.log('❌ Failed to start window selector');
45
+ process.exit(1);
46
+ }
47
+
48
+ } catch (error) {
49
+ console.error('❌ Test failed:', error.message);
50
+ process.exit(1);
51
+ }
52
+ }
53
+
54
+ testWindowSelector();
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+
3
+ const MacRecorder = require('./index.js');
4
+
5
+ async function test() {
6
+ try {
7
+ const recorder = new MacRecorder();
8
+ console.log('Getting windows directly from native binding...');
9
+
10
+ const nativeBinding = require('./build/Release/mac_recorder.node');
11
+ const nativeWindows = nativeBinding.getWindows();
12
+ console.log('Native windows:', nativeWindows.length);
13
+ if (nativeWindows.length > 0) {
14
+ console.log('First native window:', nativeWindows[0]);
15
+ }
16
+
17
+ console.log('\nGetting windows through MacRecorder class...');
18
+ const windows = await recorder.getWindows();
19
+ console.log('MacRecorder windows:', windows.length);
20
+ if (windows.length > 0) {
21
+ console.log('First MacRecorder window:', windows[0]);
22
+ }
23
+
24
+ } catch (error) {
25
+ console.error('Error:', error);
26
+ }
27
+ }
28
+
29
+ test();
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+
3
+ const MacRecorder = require('./index.js');
4
+
5
+ async function testWindowDetails() {
6
+ try {
7
+ const recorder = new MacRecorder();
8
+ const windows = await recorder.getWindows();
9
+
10
+ console.log(`Found ${windows.length} windows:`);
11
+
12
+ windows.forEach((win, i) => {
13
+ console.log(`\n${i+1}. Window ${win.id}:`);
14
+ console.log(` Title: "${win.title}"`);
15
+ console.log(` App: ${win.appName}`);
16
+ console.log(` Bundle: ${win.bundleId}`);
17
+ console.log(` Position: (${win.x}, ${win.y})`);
18
+ console.log(` Size: ${win.width} x ${win.height}`);
19
+ if (win.bounds) {
20
+ console.log(` Bounds: (${win.bounds.x}, ${win.bounds.y}) ${win.bounds.width}x${win.bounds.height}`);
21
+ }
22
+
23
+ if (i >= 10) { // Limit output
24
+ console.log(`\n... and ${windows.length - 11} more windows`);
25
+ return;
26
+ }
27
+ });
28
+
29
+ } catch (error) {
30
+ console.error('Error:', error.message);
31
+ }
32
+ }
33
+
34
+ testWindowDetails();
@@ -33,13 +33,13 @@ class WindowSelector extends EventEmitter {
33
33
  this.selectedWindow = null;
34
34
  this.lastStatus = null;
35
35
 
36
- // Electron environment detection (for logging only)
36
+ // Electron environment detection
37
37
  this.isElectron = !!(process.versions && process.versions.electron) ||
38
38
  !!(process.env.ELECTRON_VERSION) ||
39
39
  !!(process.env.ELECTRON_RUN_AS_NODE);
40
40
 
41
41
  if (this.isElectron) {
42
- console.log("🔍 WindowSelector: Detected Electron environment");
42
+ console.log("🔍 WindowSelector: Detected Electron environment - using safe mode");
43
43
  }
44
44
  }
45
45
 
@@ -174,6 +174,59 @@ class WindowSelector extends EventEmitter {
174
174
  return this.selectedWindow;
175
175
  }
176
176
 
177
+ /**
178
+ * Electron'da kullanmak için mevcut pencereleri döndürür
179
+ * @returns {Array} Available windows for selection
180
+ */
181
+ async getAvailableWindows() {
182
+ if (this.isElectron) {
183
+ try {
184
+ // Start selection to populate window list (safe mode)
185
+ const success = nativeBinding.startWindowSelection();
186
+ if (success) {
187
+ // Get the populated window list
188
+ const status = nativeBinding.getWindowSelectionStatus();
189
+
190
+ // Stop selection immediately
191
+ nativeBinding.stopWindowSelection();
192
+
193
+ // Return windows from native status
194
+ // In Electron safe mode, these will be available without overlay
195
+ const MacRecorder = require("./index.js");
196
+ const recorder = new MacRecorder();
197
+ return await recorder.getWindows();
198
+ }
199
+ } catch (error) {
200
+ console.error("Error getting available windows in Electron:", error.message);
201
+ }
202
+ }
203
+
204
+ // Fallback to regular MacRecorder method
205
+ try {
206
+ const MacRecorder = require("./index.js");
207
+ const recorder = new MacRecorder();
208
+ return await recorder.getWindows();
209
+ } catch (error) {
210
+ console.error("Error getting windows:", error.message);
211
+ return [];
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Electron'da pencere seçmek için - overlay olmadan
217
+ * @param {Object} windowInfo - Selected window from getAvailableWindows()
218
+ */
219
+ selectWindowById(windowInfo) {
220
+ if (!windowInfo || !windowInfo.id) {
221
+ throw new Error("Valid window info required");
222
+ }
223
+
224
+ this.selectedWindow = windowInfo;
225
+ this.emit('windowSelected', windowInfo);
226
+
227
+ return windowInfo;
228
+ }
229
+
177
230
  /**
178
231
  * Seçim durumunu döndürür
179
232
  */