node-mac-recorder 1.4.0 → 1.6.0

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.
@@ -14,6 +14,9 @@ Bu modül, macOS'ta sistem imleci ile pencere seçimi yapabilmenizi sağlayan g
14
14
  - **Event-driven API**: Pencere hover, seçim ve hata durumları için event'ler
15
15
  - **Window Focus Control**: Detect edilen pencereyi otomatik olarak en öne getirir
16
16
  - **Auto Bring-to-Front**: Cursor hangi pencereye gelirse otomatik focus yapar
17
+ - **Recording Preview Overlay**: Kayıt alanını görselleştiren tam ekran overlay sistemi
18
+ - **Screen Selection**: Tam ekran overlay ile ekran seçimi (menu bar dahil)
19
+ - **Screen Recording Preview**: Seçilen ekran için kayıt önizleme sistemi
17
20
  - **Permission Management**: macOS izin kontrolü ve yönetimi
18
21
 
19
22
  ## 🚀 Kurulum
@@ -175,6 +178,84 @@ selector.setBringToFrontEnabled(true); // Auto mode ON
175
178
  selector.setBringToFrontEnabled(false); // Auto mode OFF
176
179
  ```
177
180
 
181
+ ##### `async showRecordingPreview(windowInfo)`
182
+ Seçilen pencere için kayıt önizleme overlay'ini gösterir. Tüm ekranı siyah yapar, sadece pencere alanını şeffaf bırakır.
183
+
184
+ **Parameters:**
185
+ - `windowInfo` (WindowInfo) - Pencere bilgileri
186
+
187
+ **Returns:** `Promise<boolean>` - Başarı/başarısızlık
188
+
189
+ ```javascript
190
+ const success = await selector.showRecordingPreview(selectedWindow);
191
+ ```
192
+
193
+ ##### `async hideRecordingPreview()`
194
+ Kayıt önizleme overlay'ini gizler.
195
+
196
+ **Returns:** `Promise<boolean>` - Başarı/başarısızlık
197
+
198
+ ```javascript
199
+ const success = await selector.hideRecordingPreview();
200
+ ```
201
+
202
+ ##### `async startScreenSelection()`
203
+ Ekran seçim modunu başlatır. Tüm ekranları overlay ile gösterir.
204
+
205
+ **Returns:** `Promise<boolean>` - Başarı/başarısızlık
206
+
207
+ ```javascript
208
+ const success = await selector.startScreenSelection();
209
+ ```
210
+
211
+ ##### `async stopScreenSelection()`
212
+ Ekran seçim modunu durdurur.
213
+
214
+ **Returns:** `Promise<boolean>` - Başarı/başarısızlık
215
+
216
+ ```javascript
217
+ const success = await selector.stopScreenSelection();
218
+ ```
219
+
220
+ ##### `getSelectedScreen()`
221
+ Son seçilen ekran bilgisini döndürür.
222
+
223
+ **Returns:** `ScreenInfo | null`
224
+
225
+ ```javascript
226
+ const screenInfo = selector.getSelectedScreen();
227
+ ```
228
+
229
+ ##### `async selectScreen()`
230
+ Promise tabanlı ekran seçimi. Kullanıcı bir ekran seçene kadar bekler.
231
+
232
+ **Returns:** `Promise<ScreenInfo>`
233
+
234
+ ```javascript
235
+ const selectedScreen = await selector.selectScreen();
236
+ ```
237
+
238
+ ##### `async showScreenRecordingPreview(screenInfo)`
239
+ Seçilen ekran için kayıt önizleme overlay'ini gösterir. Diğer ekranları siyah yapar, sadece seçili ekranı şeffaf bırakır.
240
+
241
+ **Parameters:**
242
+ - `screenInfo` (ScreenInfo) - Ekran bilgileri
243
+
244
+ **Returns:** `Promise<boolean>` - Başarı/başarısızlık
245
+
246
+ ```javascript
247
+ const success = await selector.showScreenRecordingPreview(selectedScreen);
248
+ ```
249
+
250
+ ##### `async hideScreenRecordingPreview()`
251
+ Ekran kayıt önizleme overlay'ini gizler.
252
+
253
+ **Returns:** `Promise<boolean>` - Başarı/başarısızlık
254
+
255
+ ```javascript
256
+ const success = await selector.hideScreenRecordingPreview();
257
+ ```
258
+
178
259
  ##### `async cleanup()`
179
260
  Tüm kaynakları temizler ve seçimi durdurur.
180
261
 
@@ -267,6 +348,20 @@ selector.on('error', (error) => {
267
348
  }
268
349
  ```
269
350
 
351
+ ### ScreenInfo
352
+ ```javascript
353
+ {
354
+ id: number, // Ekran ID'si (0, 1, 2, ...)
355
+ name: string, // Ekran adı ("Display 1", "Display 2", ...)
356
+ x: number, // Global X pozisyonu
357
+ y: number, // Global Y pozisyonu
358
+ width: number, // Ekran genişliği
359
+ height: number, // Ekran yüksekliği
360
+ resolution: string, // Çözünürlük string'i ("1920x1080")
361
+ isPrimary: boolean // Ana ekran mı?
362
+ }
363
+ ```
364
+
270
365
  ## 🎮 Test Etme
271
366
 
272
367
  ### Test Dosyasını Çalıştır
@@ -298,6 +393,7 @@ node examples/window-selector-example.js --help
298
393
 
299
394
  ## ⚡ Nasıl Çalışır?
300
395
 
396
+ ### Pencere Seçim Süreci
301
397
  1. **Window Detection**: macOS `CGWindowListCopyWindowInfo` API'si ile açık pencereleri tespit eder
302
398
  2. **Cursor Tracking**: Real-time olarak imleç pozisyonunu takip eder
303
399
  3. **Overlay Rendering**: NSWindow ile transparant overlay penceresi oluşturur
@@ -306,6 +402,29 @@ node examples/window-selector-example.js --help
306
402
  6. **User Interaction**: Merkeze yerleştirilen button ile seçim yapar
307
403
  7. **Data Collection**: Seçilen pencerenin tüm bilgilerini toplar
308
404
 
405
+ ### Kayıt Önizleme Sistemi (Pencere)
406
+ 1. **Full Screen Overlay**: Tüm ekranı kaplayan siyah transparan katman oluşturur
407
+ 2. **Window Cutout**: Seçilen pencere alanını şeffaf hale getirir (cut-out effect)
408
+ 3. **Coordinate Conversion**: CGWindow koordinatlarını NSView koordinatlarına dönüştürür
409
+ 4. **Multi-Display Support**: Çoklu ekran kurulumlarında doğru pozisyonlama yapar
410
+ 5. **Non-Interactive**: Mouse events'leri geçirir, kullanıcı etkileşimini engellemeZ
411
+ 6. **Clean Management**: Programatik açma/kapama kontrolü sağlar
412
+
413
+ ### Ekran Seçim Sistemi
414
+ 1. **Multi-Screen Detection**: NSScreen.screens ile tüm ekranları tespit eder
415
+ 2. **Full Screen Coverage**: Her ekran için tam kaplama overlay oluşturur (menu bar dahil)
416
+ 3. **Interactive Overlays**: Her ekranda merkezi "Select Screen" butonu
417
+ 4. **Screen Information Display**: Ekran adı ve çözünürlük bilgilerini gösterir
418
+ 5. **Automatic Assignment**: Her overlay'i kendi ekranına otomatik atar
419
+ 6. **Selection Feedback**: Seçim yapıldığında anında geri bildirim
420
+
421
+ ### Ekran Kayıt Önizleme Sistemi
422
+ 1. **Multi-Screen Management**: Birden fazla ekranı aynı anda yönetir
423
+ 2. **Selective Darkening**: Sadece seçilmeyen ekranları siyah overlay ile kaplar
424
+ 3. **Recording Area Highlight**: Seçilen ekran tamamen şeffaf kalır
425
+ 4. **Screen-Specific Overlays**: Her ekran için ayrı overlay penceresi
426
+ 5. **Coordinate Independence**: Her ekranın kendi koordinat sistemini kullanır
427
+
309
428
  ## 🔧 Troubleshooting
310
429
 
311
430
  ### Build Hataları
@@ -334,15 +453,15 @@ if (!permissions.screenRecording) {
334
453
 
335
454
  ## 🌟 Gelişmiş Örnekler
336
455
 
337
- ### Auto Bring-to-Front (Otomatik Focus)
456
+ ### Auto Bring-to-Front (DEFAULT - Otomatik Focus)
338
457
  ```javascript
339
458
  const WindowSelector = require('./window-selector');
340
459
 
341
460
  async function autoBringToFront() {
342
461
  const selector = new WindowSelector();
343
462
 
344
- // Otomatik focus modunu aktif et
345
- selector.setBringToFrontEnabled(true);
463
+ // Auto bring-to-front varsayılan olarak AÇIK
464
+ // (Kapatmak için: selector.setBringToFrontEnabled(false))
346
465
 
347
466
  selector.on('windowEntered', (window) => {
348
467
  console.log(`🔝 Auto-focused: ${window.appName} - "${window.title}"`);
@@ -350,6 +469,7 @@ async function autoBringToFront() {
350
469
 
351
470
  await selector.startSelection();
352
471
  console.log('🖱️ Move cursor over windows - they will come to front automatically!');
472
+ console.log('💡 Only the specific window focuses, not all windows of the app');
353
473
  }
354
474
  ```
355
475
 
@@ -374,7 +494,157 @@ async function manualFocus() {
374
494
  }
375
495
  ```
376
496
 
377
- ### Otomatik Pencere Kaydı
497
+ ### Ekran Seçimi ile Kayıt
498
+ ```javascript
499
+ const WindowSelector = require('./window-selector');
500
+ const MacRecorder = require('./index');
501
+
502
+ async function recordScreenWithPreview() {
503
+ const selector = new WindowSelector();
504
+ const recorder = new MacRecorder();
505
+
506
+ try {
507
+ // Ekran seç
508
+ const screen = await selector.selectScreen();
509
+ console.log(`Selected: ${screen.name} (${screen.resolution})`);
510
+
511
+ // Kayıt önizlemesi göster (diğer ekranlar siyah, seçili ekran şeffaf)
512
+ await selector.showScreenRecordingPreview(screen);
513
+ console.log('🎬 Screen recording preview shown');
514
+
515
+ // 3 saniye bekle
516
+ await new Promise(resolve => setTimeout(resolve, 3000));
517
+
518
+ // Ekran kaydını başlat
519
+ const outputPath = `./recordings/screen-${screen.id}-${Date.now()}.mov`;
520
+ await recorder.startRecording(outputPath, {
521
+ displayId: screen.id,
522
+ captureCursor: true,
523
+ includeMicrophone: true
524
+ });
525
+
526
+ console.log('🔴 Screen recording started...');
527
+
528
+ // 10 saniye kaydet
529
+ setTimeout(async () => {
530
+ await recorder.stopRecording();
531
+
532
+ // Önizleme overlay'ini gizle
533
+ await selector.hideScreenRecordingPreview();
534
+ console.log(`✅ Recording saved: ${outputPath}`);
535
+ }, 10000);
536
+
537
+ } finally {
538
+ await selector.cleanup();
539
+ }
540
+ }
541
+ ```
542
+
543
+ ### Kayıt Önizleme ile Pencere Kaydı
544
+ ```javascript
545
+ const WindowSelector = require('./window-selector');
546
+ const MacRecorder = require('./index');
547
+
548
+ async function recordWithPreview() {
549
+ const selector = new WindowSelector();
550
+ const recorder = new MacRecorder();
551
+
552
+ try {
553
+ // Pencere seç
554
+ const window = await selector.selectWindow();
555
+ console.log(`Selected: ${window.title}`);
556
+
557
+ // Kayıt önizlemesi göster (siyah overlay + şeffaf pencere alanı)
558
+ await selector.showRecordingPreview(window);
559
+ console.log('🎬 Recording preview shown - you can see exact recording area');
560
+
561
+ // 3 saniye bekle (kullanıcı görebilsin)
562
+ await new Promise(resolve => setTimeout(resolve, 3000));
563
+
564
+ // Kaydı başlat
565
+ const outputPath = `./recordings/${window.appName}-${Date.now()}.mov`;
566
+ await recorder.startRecording(outputPath, {
567
+ windowId: window.id,
568
+ captureCursor: true,
569
+ includeMicrophone: true
570
+ });
571
+
572
+ console.log('🔴 Recording started...');
573
+
574
+ // 10 saniye kaydet
575
+ setTimeout(async () => {
576
+ await recorder.stopRecording();
577
+
578
+ // Önizleme overlay'ini gizle
579
+ await selector.hideRecordingPreview();
580
+ console.log(`✅ Recording saved: ${outputPath}`);
581
+ }, 10000);
582
+
583
+ } finally {
584
+ await selector.cleanup();
585
+ }
586
+ }
587
+ ```
588
+
589
+ ### Basit Ekran Seçimi
590
+ ```javascript
591
+ const WindowSelector = require('./window-selector');
592
+
593
+ async function selectScreen() {
594
+ const selector = new WindowSelector();
595
+
596
+ try {
597
+ console.log('Bir ekran seçin...');
598
+ const selectedScreen = await selector.selectScreen();
599
+
600
+ console.log('Seçilen ekran:', {
601
+ name: selectedScreen.name,
602
+ resolution: selectedScreen.resolution,
603
+ position: `(${selectedScreen.x}, ${selectedScreen.y})`,
604
+ isPrimary: selectedScreen.isPrimary
605
+ });
606
+
607
+ return selectedScreen;
608
+
609
+ } catch (error) {
610
+ console.error('Hata:', error.message);
611
+ } finally {
612
+ await selector.cleanup();
613
+ }
614
+ }
615
+ ```
616
+
617
+ ### Manuel Ekran Kontrolü
618
+ ```javascript
619
+ const WindowSelector = require('./window-selector');
620
+
621
+ async function manualScreenSelection() {
622
+ const selector = new WindowSelector();
623
+
624
+ try {
625
+ // Ekran seçimini başlat
626
+ await selector.startScreenSelection();
627
+ console.log('🖥️ Screen overlays shown - click Select Screen button');
628
+
629
+ // Polling ile seçim bekle
630
+ const checkSelection = () => {
631
+ const selected = selector.getSelectedScreen();
632
+ if (selected) {
633
+ console.log(`✅ Screen selected: ${selected.name}`);
634
+ return selected;
635
+ }
636
+ setTimeout(checkSelection, 100);
637
+ };
638
+
639
+ checkSelection();
640
+
641
+ } catch (error) {
642
+ console.error('Hata:', error.message);
643
+ }
644
+ }
645
+ ```
646
+
647
+ ### Otomatik Pencere Kaydı (Basit)
378
648
  ```javascript
379
649
  const WindowSelector = require('./window-selector');
380
650
  const MacRecorder = require('./index');
@@ -449,6 +719,7 @@ Bu modül ana projenin lisansı altındadır.
449
719
 
450
720
  ## ⭐ Özellik İstekleri
451
721
 
722
+ ### Pencere Seçimi
452
723
  - [ ] Pencere gruplandırma
453
724
  - [ ] Hotkey desteği
454
725
  - [ ] Pencere filtreleme
@@ -456,6 +727,14 @@ Bu modül ana projenin lisansı altındadır.
456
727
  - [ ] Screenshot alma
457
728
  - [ ] Window history
458
729
 
730
+ ### Ekran Seçimi
731
+ - [x] Tam ekran overlay (menu bar dahil) ✅
732
+ - [x] Multi-display desteği ✅
733
+ - [x] Kayıt önizleme sistemi ✅
734
+ - [ ] Hotkey desteği
735
+ - [ ] Çoklu ekran seçimi
736
+ - [ ] Ekran thumbnail'ları
737
+
459
738
  ---
460
739
 
461
740
  **Not**: Bu modül sadece macOS'ta çalışır ve sistem izinleri gerektirir.
package/debug-test.js ADDED
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+
3
+ const WindowSelector = require('./window-selector');
4
+
5
+ async function debugTest() {
6
+ console.log('🔍 Debug Window Selector Test');
7
+ console.log('==============================\n');
8
+
9
+ const selector = new WindowSelector();
10
+
11
+ try {
12
+ // İzinleri kontrol et
13
+ console.log('📋 Checking permissions...');
14
+ const permissions = await selector.checkPermissions();
15
+ console.log('Permissions:', JSON.stringify(permissions, null, 2));
16
+
17
+ if (!permissions.screenRecording || !permissions.accessibility) {
18
+ console.log('\n❌ MISSING PERMISSIONS!');
19
+ console.log('Please enable in System Preferences > Security & Privacy:');
20
+ console.log(' ✓ Screen Recording - Add Terminal/your IDE');
21
+ console.log(' ✓ Accessibility - Add Terminal/your IDE');
22
+ console.log('\nAfter enabling permissions, restart this test.');
23
+ return;
24
+ }
25
+
26
+ console.log('✅ Permissions OK\n');
27
+
28
+ // Debug mode ile başlat
29
+ console.log('🚀 Starting selection with debug info...');
30
+ await selector.startSelection();
31
+
32
+ let windowCount = 0;
33
+
34
+ selector.on('windowEntered', (window) => {
35
+ windowCount++;
36
+ console.log(`\n[${windowCount}] 🎯 WINDOW DETECTED:`);
37
+ console.log(` App: ${window.appName}`);
38
+ console.log(` Title: "${window.title}"`);
39
+ console.log(` ID: ${window.id}`);
40
+ console.log(` Position: (${window.x}, ${window.y})`);
41
+ console.log(` Size: ${window.width} × ${window.height}`);
42
+ console.log(` 🔝 Should auto-focus now...`);
43
+ });
44
+
45
+ selector.on('windowLeft', (window) => {
46
+ console.log(`\n🚪 LEFT WINDOW: ${window.appName} - "${window.title}"`);
47
+ });
48
+
49
+ selector.on('error', (error) => {
50
+ console.error('\n❌ ERROR:', error.message);
51
+ });
52
+
53
+ console.log('📋 Test Instructions:');
54
+ console.log(' 1. Move cursor over different application windows');
55
+ console.log(' 2. You should see:');
56
+ console.log(' - Blue overlay rectangle around windows');
57
+ console.log(' - "Select Window" button in center');
58
+ console.log(' - Windows automatically coming to front');
59
+ console.log(' 3. If overlay not visible, check permissions');
60
+ console.log(' 4. Press Ctrl+C to exit\n');
61
+ console.log('🖱️ START MOVING CURSOR NOW...\n');
62
+
63
+ // Status monitoring
64
+ let statusCount = 0;
65
+ setInterval(() => {
66
+ statusCount++;
67
+ const status = selector.getStatus();
68
+
69
+ if (statusCount % 50 === 0) { // Every 5 seconds
70
+ console.log(`⏱️ Status Check #${statusCount/50}:`);
71
+ console.log(` - Selecting: ${status.isSelecting}`);
72
+ console.log(` - Windows found: ${status.nativeStatus?.windowCount || 0}`);
73
+ console.log(` - Overlay active: ${status.nativeStatus?.hasOverlay || false}`);
74
+ if (status.nativeStatus?.currentWindow) {
75
+ console.log(` - Current: ${status.nativeStatus.currentWindow.appName}`);
76
+ }
77
+ console.log('');
78
+ }
79
+ }, 100);
80
+
81
+ } catch (error) {
82
+ console.error('❌ Fatal Error:', error.message);
83
+ console.error(error.stack);
84
+ }
85
+ }
86
+
87
+ // Handle Ctrl+C gracefully
88
+ process.on('SIGINT', async () => {
89
+ console.log('\n\n🛑 Stopping debug test...');
90
+ process.exit(0);
91
+ });
92
+
93
+ if (require.main === module) {
94
+ debugTest();
95
+ }
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+
3
+ const WindowSelector = require('./window-selector');
4
+
5
+ async function testDefaultAutoBringToFront() {
6
+ console.log('🔝 Default Auto Bring-To-Front Test');
7
+ console.log('====================================\n');
8
+
9
+ const selector = new WindowSelector();
10
+
11
+ try {
12
+ console.log('🚀 Starting window selector with DEFAULT auto bring-to-front...');
13
+ console.log('(Auto bring-to-front is now enabled by default)\n');
14
+
15
+ console.log('📋 Instructions:');
16
+ console.log(' • Move cursor over different windows');
17
+ console.log(' • Each window should automatically come to front');
18
+ console.log(' • Only the specific window should focus (not whole app)');
19
+ console.log(' • Press D to disable auto mode');
20
+ console.log(' • Press E to re-enable auto mode');
21
+ console.log(' • Press Ctrl+C to exit\n');
22
+
23
+ let windowCount = 0;
24
+ let lastWindowId = null;
25
+
26
+ selector.on('windowEntered', (window) => {
27
+ if (window.id !== lastWindowId) {
28
+ windowCount++;
29
+ console.log(`[${windowCount}] 🎯 WINDOW: ${window.appName} - "${window.title}"`);
30
+ console.log(` 📍 Position: (${window.x}, ${window.y})`);
31
+ console.log(` 📏 Size: ${window.width} × ${window.height}`);
32
+ console.log(` 🔝 Should auto-focus THIS specific window only!`);
33
+ lastWindowId = window.id;
34
+ }
35
+ });
36
+
37
+ selector.on('windowLeft', (window) => {
38
+ console.log(`🚪 Left: ${window.appName} - "${window.title}"\n`);
39
+ });
40
+
41
+ // Keyboard controls
42
+ const readline = require('readline');
43
+ readline.emitKeypressEvents(process.stdin);
44
+ if (process.stdin.isTTY) {
45
+ process.stdin.setRawMode(true);
46
+ }
47
+
48
+ process.stdin.on('keypress', async (str, key) => {
49
+ if (key.name === 'd') {
50
+ console.log('\n🔄 Disabling auto bring-to-front...');
51
+ selector.setBringToFrontEnabled(false);
52
+ console.log(' ✅ Auto mode OFF - Windows will not auto-focus');
53
+ } else if (key.name === 'e') {
54
+ console.log('\n🔄 Enabling auto bring-to-front...');
55
+ selector.setBringToFrontEnabled(true);
56
+ console.log(' ✅ Auto mode ON - Windows will auto-focus again');
57
+ } else if (key.ctrl && key.name === 'c') {
58
+ console.log('\n\n🛑 Stopping...');
59
+ console.log(`📊 Total windows encountered: ${windowCount}`);
60
+ await selector.cleanup();
61
+ process.exit(0);
62
+ }
63
+ });
64
+
65
+ await selector.startSelection();
66
+
67
+ // Status update every 10 seconds
68
+ setInterval(() => {
69
+ console.log(`\n⏱️ Status: ${windowCount} windows encountered so far`);
70
+ console.log(' (Continue moving cursor over windows to test auto-focus)');
71
+ }, 10000);
72
+
73
+ // Keep running
74
+ setInterval(() => {}, 1000);
75
+
76
+ } catch (error) {
77
+ console.error('❌ Error:', error.message);
78
+ console.error(error.stack);
79
+ } finally {
80
+ await selector.cleanup();
81
+ }
82
+ }
83
+
84
+ if (require.main === module) {
85
+ testDefaultAutoBringToFront();
86
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [