node-mac-recorder
Version:
Native macOS screen recording package for Node.js applications
745 lines (566 loc) • 21.5 kB
Markdown
# Window Selector
**macOS Window Selection Tool with Real-time Visual Overlay**
Bu modül, macOS'ta sistem imleci ile pencere seçimi yapabilmenizi sağlayan güçlü bir araçtır. İmleç hangi pencerenin üstüne gelirse, o pencereyi mavi kapsayıcı ile highlight eder ve merkeze yerleştirilen "Select Window" butonu ile seçim yapabilirsiniz.
## ✨ Özellikler
- **Real-time Window Detection**: İmleç hangi pencereye gelirse otomatik olarak tespit eder
- **Visual Overlay**: Seçilebilir pencereleri mavi transparant kapsayıcı ile highlight eder
- **Interactive Selection**: Merkeze yerleştirilen "Start Record" butonu ile kolay seçim
- **Multi-display Support**: Çoklu ekran kurulumlarında çalışır
- **Detailed Window Info**: Pencere pozisyonu, boyutu ve hangi ekranda olduğunu döndürür
- **Event-driven API**: Pencere hover, seçim ve hata durumları için event'ler
- **Window Focus Control**: Detect edilen pencereyi otomatik olarak en öne getirir
- **Auto Bring-to-Front**: Cursor hangi pencereye gelirse otomatik focus yapar
- **Recording Preview Overlay**: Kayıt alanını görselleştiren tam ekran overlay sistemi
- **Screen Selection**: Tam ekran overlay ile ekran seçimi (menu bar dahil, ESC ile iptal)
- **Screen Recording Preview**: Seçilen ekran için kayıt önizleme sistemi
- **ESC Key Support**: Tüm seçim modlarında ESC tuşu ile iptal
- **Permission Management**: macOS izin kontrolü ve yönetimi
## 🚀 Kurulum
```bash
# Ana proje dizininde
npm install
# Native modülü build edin
npm run build
```
## 📋 Sistem Gereksinimleri
- **macOS 10.15+** (Catalina veya üzeri)
- **Node.js 14+**
- **Xcode Command Line Tools**
- **System Permissions**:
- Screen Recording permission
- Accessibility permission
## 🔐 İzinler
İlk kullanımda macOS aşağıdaki izinleri isteyecektir:
1. **System Preferences > Security & Privacy > Privacy > Screen Recording**
- Terminal veya kullandığınız IDE'yi (VSCode, WebStorm, vb.) etkinleştirin
2. **System Preferences > Security & Privacy > Privacy > Accessibility**
- Terminal veya kullandığınız IDE'yi etkinleştirin
## 🎯 Temel Kullanım
### Basit Pencere Seçimi
```javascript
const WindowSelector = require('./window-selector');
async function selectWindow() {
const selector = new WindowSelector();
try {
console.log('Bir pencere seçin (ESC ile iptal)...');
const selectedWindow = await selector.selectWindow();
console.log('Seçilen pencere:', {
title: selectedWindow.title,
app: selectedWindow.appName,
position: `(${selectedWindow.x}, ${selectedWindow.y})`,
size: `${selectedWindow.width}x${selectedWindow.height}`,
screen: selectedWindow.screenId
});
return selectedWindow;
} catch (error) {
console.error('Hata:', error.message);
} finally {
await selector.cleanup();
}
}
selectWindow();
```
### Manuel Kontrol
```javascript
const WindowSelector = require('./window-selector');
async function manualSelection() {
const selector = new WindowSelector();
// Event listener'lar
selector.on('windowEntered', (window) => {
console.log(`Pencere üstünde: ${window.title} (${window.appName})`);
});
selector.on('windowSelected', (window) => {
console.log(`Seçildi: ${window.title}`);
});
// Seçimi başlat
await selector.startSelection();
// Kullanıcı seçim yapana kadar bekle
// Seçim tamamlandığında 'windowSelected' event'i tetiklenir
// Seçimi durdurmak için:
// await selector.stopSelection();
}
```
## 📚 API Reference
### WindowSelector Class
#### Constructor
```javascript
const selector = new WindowSelector();
```
#### Methods
##### `async selectWindow()`
Promise tabanlı pencere seçimi. Kullanıcı bir pencere seçene kadar bekler.
**Returns:** `Promise<WindowInfo>`
```javascript
const window = await selector.selectWindow();
```
##### `async startSelection()`
Pencere seçim modunu başlatır.
**Returns:** `Promise<boolean>`
##### `async stopSelection()`
Pencere seçim modunu durdurur.
**Returns:** `Promise<boolean>`
##### `getSelectedWindow()`
Son seçilen pencere bilgisini döndürür.
**Returns:** `WindowInfo | null`
##### `getStatus()`
Seçici durumunu döndürür.
**Returns:** `SelectionStatus`
##### `async checkPermissions()`
macOS izinlerini kontrol eder.
**Returns:** `Promise<PermissionStatus>`
##### `async bringWindowToFront(windowId)`
Belirtilen pencereyi en öne getirir (focus yapar).
**Parameters:**
- `windowId` (number) - Window ID
**Returns:** `Promise<boolean>` - Başarı/başarısızlık
```javascript
const success = await selector.bringWindowToFront(windowInfo.id);
```
##### `setBringToFrontEnabled(enabled)`
Otomatik pencere en öne getirme özelliğini aktif/pasif yapar.
**Parameters:**
- `enabled` (boolean) - Enable/disable
```javascript
selector.setBringToFrontEnabled(true); // Auto mode ON
selector.setBringToFrontEnabled(false); // Auto mode OFF
```
##### `async showRecordingPreview(windowInfo)`
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.
**Parameters:**
- `windowInfo` (WindowInfo) - Pencere bilgileri
**Returns:** `Promise<boolean>` - Başarı/başarısızlık
```javascript
const success = await selector.showRecordingPreview(selectedWindow);
```
##### `async hideRecordingPreview()`
Kayıt önizleme overlay'ini gizler.
**Returns:** `Promise<boolean>` - Başarı/başarısızlık
```javascript
const success = await selector.hideRecordingPreview();
```
##### `async startScreenSelection()`
Ekran seçim modunu başlatır. Tüm ekranları overlay ile gösterir.
**Returns:** `Promise<boolean>` - Başarı/başarısızlık
```javascript
const success = await selector.startScreenSelection();
```
##### `async stopScreenSelection()`
Ekran seçim modunu durdurur.
**Returns:** `Promise<boolean>` - Başarı/başarısızlık
```javascript
const success = await selector.stopScreenSelection();
```
##### `getSelectedScreen()`
Son seçilen ekran bilgisini döndürür.
**Returns:** `ScreenInfo | null`
```javascript
const screenInfo = selector.getSelectedScreen();
```
##### `async selectScreen()`
Promise tabanlı ekran seçimi. Kullanıcı bir ekran seçene kadar bekler.
**Returns:** `Promise<ScreenInfo>`
```javascript
const selectedScreen = await selector.selectScreen();
```
##### `async showScreenRecordingPreview(screenInfo)`
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.
**Parameters:**
- `screenInfo` (ScreenInfo) - Ekran bilgileri
**Returns:** `Promise<boolean>` - Başarı/başarısızlık
```javascript
const success = await selector.showScreenRecordingPreview(selectedScreen);
```
##### `async hideScreenRecordingPreview()`
Ekran kayıt önizleme overlay'ini gizler.
**Returns:** `Promise<boolean>` - Başarı/başarısızlık
```javascript
const success = await selector.hideScreenRecordingPreview();
```
##### `async cleanup()`
Tüm kaynakları temizler ve seçimi durdurur.
#### Events
##### `selectionStarted`
Seçim modu başladığında tetiklenir.
```javascript
selector.on('selectionStarted', () => {
console.log('Seçim başladı');
});
```
##### `windowEntered`
İmleç bir pencereye geldiğinde tetiklenir.
```javascript
selector.on('windowEntered', (windowInfo) => {
console.log(`Pencere: ${windowInfo.title}`);
});
```
##### `windowLeft`
İmleç bir pencereden ayrıldığında tetiklenir.
```javascript
selector.on('windowLeft', (windowInfo) => {
console.log(`Ayrıldı: ${windowInfo.title}`);
});
```
##### `windowSelected`
Bir pencere seçildiğinde tetiklenir.
```javascript
selector.on('windowSelected', (windowInfo) => {
console.log('Seçilen pencere:', windowInfo);
});
```
##### `selectionStopped`
Seçim modu durduğunda tetiklenir.
##### `error`
Bir hata oluştuğunda tetiklenir.
```javascript
selector.on('error', (error) => {
console.error('Hata:', error.message);
});
```
## 📊 Data Types
### WindowInfo
```javascript
{
id: number, // Pencere ID'si
title: string, // Pencere başlığı
appName: string, // Uygulama adı
x: number, // Global X pozisyonu
y: number, // Global Y pozisyonu
width: number, // Pencere genişliği
height: number, // Pencere yüksekliği
screenId: number, // Hangi ekranda olduğu
screenX: number, // Ekranın X pozisyonu
screenY: number, // Ekranın Y pozisyonu
screenWidth: number, // Ekran genişliği
screenHeight: number // Ekran yüksekliği
}
```
### SelectionStatus
```javascript
{
isSelecting: boolean, // Seçim modunda mı?
hasSelectedWindow: boolean, // Seçilmiş pencere var mı?
selectedWindow: WindowInfo | null,
nativeStatus: object // Native durum bilgisi
}
```
### PermissionStatus
```javascript
{
screenRecording: boolean, // Ekran kaydı izni
accessibility: boolean, // Erişilebilirlik izni
microphone: boolean // Mikrofon izni
}
```
### ScreenInfo
```javascript
{
id: number, // Ekran ID'si (0, 1, 2, ...)
name: string, // Ekran adı ("Display 1", "Display 2", ...)
x: number, // Global X pozisyonu
y: number, // Global Y pozisyonu
width: number, // Ekran genişliği
height: number, // Ekran yüksekliği
resolution: string, // Çözünürlük string'i ("1920x1080")
isPrimary: boolean // Ana ekran mı?
}
```
## 🎮 Test Etme
### Test Dosyasını Çalıştır
```bash
# Interaktif test
node window-selector-test.js
# API test modu
node window-selector-test.js --api-test
```
### Örnekleri Çalıştır
```bash
# Basit örnek
node examples/window-selector-example.js
# Gelişmiş örnek (event'lerle)
node examples/window-selector-example.js --advanced
# Çoklu seçim
node examples/window-selector-example.js --multiple
# Detaylı analiz
node examples/window-selector-example.js --analysis
# Yardım
node examples/window-selector-example.js --help
```
## ⚡ Nasıl Çalışır?
### Pencere Seçim Süreci
1. **Window Detection**: macOS `CGWindowListCopyWindowInfo` API'si ile açık pencereleri tespit eder
2. **Cursor Tracking**: Real-time olarak imleç pozisyonunu takip eder
3. **Overlay Rendering**: NSWindow ile transparant overlay penceresi oluşturur
4. **Hit Testing**: İmlecin hangi pencere üstünde olduğunu hesaplar
5. **Visual Feedback**: Pencereyi highlight eden mavi kapsayıcı çizer
6. **User Interaction**: Merkeze yerleştirilen button ile seçim yapar
7. **Data Collection**: Seçilen pencerenin tüm bilgilerini toplar
### Kayıt Önizleme Sistemi (Pencere)
1. **Full Screen Overlay**: Tüm ekranı kaplayan siyah transparan katman oluşturur
2. **Window Cutout**: Seçilen pencere alanını şeffaf hale getirir (cut-out effect)
3. **Coordinate Conversion**: CGWindow koordinatlarını NSView koordinatlarına dönüştürür
4. **Multi-Display Support**: Çoklu ekran kurulumlarında doğru pozisyonlama yapar
5. **Non-Interactive**: Mouse events'leri geçirir, kullanıcı etkileşimini engellemeZ
6. **Clean Management**: Programatik açma/kapama kontrolü sağlar
### Ekran Seçim Sistemi
1. **Multi-Screen Detection**: NSScreen.screens ile tüm ekranları tespit eder
2. **Full Screen Coverage**: Her ekran için tam kaplama overlay oluşturur (menu bar dahil)
3. **Interactive Overlays**: Her ekranda merkezi "Select Screen" butonu
4. **Screen Information Display**: Ekran adı ve çözünürlük bilgilerini gösterir
5. **Automatic Assignment**: Her overlay'i kendi ekranına otomatik atar
6. **Selection Feedback**: Seçim yapıldığında anında geri bildirim
### Ekran Kayıt Önizleme Sistemi
1. **Multi-Screen Management**: Birden fazla ekranı aynı anda yönetir
2. **Selective Darkening**: Sadece seçilmeyen ekranları siyah overlay ile kaplar
3. **Recording Area Highlight**: Seçilen ekran tamamen şeffaf kalır
4. **Screen-Specific Overlays**: Her ekran için ayrı overlay penceresi
5. **Coordinate Independence**: Her ekranın kendi koordinat sistemini kullanır
## 🔧 Troubleshooting
### Build Hataları
```bash
# Xcode Command Line Tools'u yükle
xcode-select --install
# Node-gyp'i yeniden build et
npm run clean
npm run build
```
### İzin Hataları
1. **System Preferences > Security & Privacy > Privacy** bölümüne git
2. **Screen Recording** ve **Accessibility** sekmelerinde Terminal'i etkinleştir
3. Uygulamayı yeniden başlat
### Runtime Hataları
```javascript
// İzinleri kontrol et
const permissions = await selector.checkPermissions();
if (!permissions.screenRecording) {
console.log('Screen recording permission required');
}
```
## 🌟 Gelişmiş Örnekler
### Auto Bring-to-Front (DEFAULT - Otomatik Focus)
```javascript
const WindowSelector = require('./window-selector');
async function autoBringToFront() {
const selector = new WindowSelector();
// Auto bring-to-front varsayılan olarak AÇIK
// (Kapatmak için: selector.setBringToFrontEnabled(false))
selector.on('windowEntered', (window) => {
console.log(`🔝 Auto-focused: ${window.appName} - "${window.title}"`);
});
await selector.startSelection();
console.log('🖱️ Move cursor over windows - they will come to front automatically!');
console.log('💡 Only the specific window focuses, not all windows of the app');
}
```
### Manuel Window Focus
```javascript
const WindowSelector = require('./window-selector');
async function manualFocus() {
const selector = new WindowSelector();
selector.on('windowEntered', async (window) => {
console.log(`Found: ${window.appName} - "${window.title}"`);
// Manuel olarak pencereyi en öne getir
const success = await selector.bringWindowToFront(window.id);
if (success) {
console.log('✅ Window brought to front!');
}
});
await selector.startSelection();
}
```
### Ekran Seçimi ile Kayıt
```javascript
const WindowSelector = require('./window-selector');
const MacRecorder = require('./index');
async function recordScreenWithPreview() {
const selector = new WindowSelector();
const recorder = new MacRecorder();
try {
// Ekran seç
const screen = await selector.selectScreen();
console.log(`Selected: ${screen.name} (${screen.resolution})`);
// Kayıt önizlemesi göster (diğer ekranlar siyah, seçili ekran şeffaf)
await selector.showScreenRecordingPreview(screen);
console.log('🎬 Screen recording preview shown');
// 3 saniye bekle
await new Promise(resolve => setTimeout(resolve, 3000));
// Ekran kaydını başlat
const outputPath = `./recordings/screen-${screen.id}-${Date.now()}.mov`;
await recorder.startRecording(outputPath, {
displayId: screen.id,
captureCursor: true,
includeMicrophone: true
});
console.log('🔴 Screen recording started...');
// 10 saniye kaydet
setTimeout(async () => {
await recorder.stopRecording();
// Önizleme overlay'ini gizle
await selector.hideScreenRecordingPreview();
console.log(`✅ Recording saved: ${outputPath}`);
}, 10000);
} finally {
await selector.cleanup();
}
}
```
### Kayıt Önizleme ile Pencere Kaydı
```javascript
const WindowSelector = require('./window-selector');
const MacRecorder = require('./index');
async function recordWithPreview() {
const selector = new WindowSelector();
const recorder = new MacRecorder();
try {
// Pencere seç
const window = await selector.selectWindow();
console.log(`Selected: ${window.title}`);
// Kayıt önizlemesi göster (siyah overlay + şeffaf pencere alanı)
await selector.showRecordingPreview(window);
console.log('🎬 Recording preview shown - you can see exact recording area');
// 3 saniye bekle (kullanıcı görebilsin)
await new Promise(resolve => setTimeout(resolve, 3000));
// Kaydı başlat
const outputPath = `./recordings/${window.appName}-${Date.now()}.mov`;
await recorder.startRecording(outputPath, {
windowId: window.id,
captureCursor: true,
includeMicrophone: true
});
console.log('🔴 Recording started...');
// 10 saniye kaydet
setTimeout(async () => {
await recorder.stopRecording();
// Önizleme overlay'ini gizle
await selector.hideRecordingPreview();
console.log(`✅ Recording saved: ${outputPath}`);
}, 10000);
} finally {
await selector.cleanup();
}
}
```
### Basit Ekran Seçimi
```javascript
const WindowSelector = require('./window-selector');
async function selectScreen() {
const selector = new WindowSelector();
try {
console.log('Bir ekran seçin (ESC ile iptal)...');
const selectedScreen = await selector.selectScreen();
console.log('Seçilen ekran:', {
name: selectedScreen.name,
resolution: selectedScreen.resolution,
position: `(${selectedScreen.x}, ${selectedScreen.y})`,
isPrimary: selectedScreen.isPrimary
});
return selectedScreen;
} catch (error) {
if (error.message.includes('cancelled')) {
console.log('❌ Seçim iptal edildi');
} else {
console.error('Hata:', error.message);
}
} finally {
await selector.cleanup();
}
}
```
### Manuel Ekran Kontrolü
```javascript
const WindowSelector = require('./window-selector');
async function manualScreenSelection() {
const selector = new WindowSelector();
try {
// Ekran seçimini başlat
await selector.startScreenSelection();
console.log('🖥️ Screen overlays shown - click Start Record button (ESC to cancel)');
// Polling ile seçim bekle
const checkSelection = () => {
const selected = selector.getSelectedScreen();
if (selected) {
console.log(`✅ Screen selected: ${selected.name}`);
return selected;
}
setTimeout(checkSelection, 100);
};
checkSelection();
} catch (error) {
console.error('Hata:', error.message);
}
}
```
### Otomatik Pencere Kaydı (Basit)
```javascript
const WindowSelector = require('./window-selector');
const MacRecorder = require('./index');
async function recordSelectedWindow() {
const selector = new WindowSelector();
const recorder = new MacRecorder();
try {
// Pencere seç
const window = await selector.selectWindow();
console.log(`Recording: ${window.title}`);
// Seçilen pencereyi kaydet
const outputPath = `./recordings/${window.appName}-${Date.now()}.mov`;
await recorder.startRecording(outputPath, {
windowId: window.id,
captureCursor: true,
includeMicrophone: true
});
// 10 saniye kaydet
setTimeout(async () => {
await recorder.stopRecording();
console.log(`Recording saved: ${outputPath}`);
}, 10000);
} finally {
await selector.cleanup();
}
}
```
### Pencere Monitoring
```javascript
const WindowSelector = require('./window-selector');
async function monitorWindowChanges() {
const selector = new WindowSelector();
const visitedWindows = new Set();
selector.on('windowEntered', (window) => {
const key = `${window.appName}-${window.title}`;
if (!visitedWindows.has(key)) {
visitedWindows.add(key);
console.log(`Yeni pencere keşfedildi: ${window.title} (${window.appName})`);
}
});
await selector.startSelection();
// İptal etmek için Ctrl+C
process.on('SIGINT', async () => {
console.log(`\nToplam keşfedilen pencere: ${visitedWindows.size}`);
await selector.cleanup();
process.exit(0);
});
}
```
## 📄 Lisans
Bu modül ana projenin lisansı altındadır.
## 🤝 Katkıda Bulunma
1. Fork edin
2. Feature branch oluşturun (`git checkout -b feature/amazing-feature`)
3. Commit edin (`git commit -m 'Add amazing feature'`)
4. Push edin (`git push origin feature/amazing-feature`)
5. Pull Request açın
## ⭐ Özellik İstekleri
### Pencere Seçimi
- [ ] Pencere gruplandırma
- [ ] Hotkey desteği
- [ ] Pencere filtreleme
- [ ] Çoklu seçim modu
- [ ] Screenshot alma
- [ ] Window history
### Ekran Seçimi
- [x] Tam ekran overlay (menu bar dahil) ✅
- [x] Multi-display desteği ✅
- [x] Kayıt önizleme sistemi ✅
- [ ] Hotkey desteği
- [ ] Çoklu ekran seçimi
- [ ] Ekran thumbnail'ları
---
**Not**: Bu modül sadece macOS'ta çalışır ve sistem izinleri gerektirir.