Skip to content

Latest commit

 

History

History
745 lines (566 loc) · 21 KB

File metadata and controls

745 lines (566 loc) · 21 KB

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

# 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

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

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

const selector = new WindowSelector();

Methods

async selectWindow()

Promise tabanlı pencere seçimi. Kullanıcı bir pencere seçene kadar bekler.

Returns: Promise<WindowInfo>

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

const success = await selector.bringWindowToFront(windowInfo.id);
setBringToFrontEnabled(enabled)

Otomatik pencere en öne getirme özelliğini aktif/pasif yapar.

Parameters:

  • enabled (boolean) - Enable/disable
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

const success = await selector.showRecordingPreview(selectedWindow);
async hideRecordingPreview()

Kayıt önizleme overlay'ini gizler.

Returns: Promise<boolean> - Başarı/başarısızlık

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

const success = await selector.startScreenSelection();
async stopScreenSelection()

Ekran seçim modunu durdurur.

Returns: Promise<boolean> - Başarı/başarısızlık

const success = await selector.stopScreenSelection();
getSelectedScreen()

Son seçilen ekran bilgisini döndürür.

Returns: ScreenInfo | null

const screenInfo = selector.getSelectedScreen();
async selectScreen()

Promise tabanlı ekran seçimi. Kullanıcı bir ekran seçene kadar bekler.

Returns: Promise<ScreenInfo>

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

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

const success = await selector.hideScreenRecordingPreview();
async cleanup()

Tüm kaynakları temizler ve seçimi durdurur.

Events

selectionStarted

Seçim modu başladığında tetiklenir.

selector.on('selectionStarted', () => {
    console.log('Seçim başladı');
});
windowEntered

İmleç bir pencereye geldiğinde tetiklenir.

selector.on('windowEntered', (windowInfo) => {
    console.log(`Pencere: ${windowInfo.title}`);
});
windowLeft

İmleç bir pencereden ayrıldığında tetiklenir.

selector.on('windowLeft', (windowInfo) => {
    console.log(`Ayrıldı: ${windowInfo.title}`);
});
windowSelected

Bir pencere seçildiğinde tetiklenir.

selector.on('windowSelected', (windowInfo) => {
    console.log('Seçilen pencere:', windowInfo);
});
selectionStopped

Seçim modu durduğunda tetiklenir.

error

Bir hata oluştuğunda tetiklenir.

selector.on('error', (error) => {
    console.error('Hata:', error.message);
});

📊 Data Types

WindowInfo

{
    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

{
    isSelecting: boolean,      // Seçim modunda mı?
    hasSelectedWindow: boolean, // Seçilmiş pencere var mı?
    selectedWindow: WindowInfo | null,
    nativeStatus: object       // Native durum bilgisi
}

PermissionStatus

{
    screenRecording: boolean,  // Ekran kaydı izni
    accessibility: boolean,    // Erişilebilirlik izni
    microphone: boolean       // Mikrofon izni
}

ScreenInfo

{
    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

# Interaktif test
node window-selector-test.js

# API test modu
node window-selector-test.js --api-test

Örnekleri Çalıştır

# 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ı

# 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ı

// İ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)

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

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

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ı

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

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ü

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)

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

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

  • Tam ekran overlay (menu bar dahil) ✅
  • Multi-display desteği ✅
  • 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.