node-mac-recorder 2.4.11 → 2.4.13
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/binding.gyp +5 -12
- package/index.js +25 -104
- package/install.js +2 -19
- package/package.json +2 -6
- package/src/audio_capture.mm +40 -96
- package/src/cursor_tracker.mm +4 -3
- package/src/mac_recorder.mm +673 -753
- package/src/screen_capture.h +0 -5
- package/src/screen_capture.mm +60 -139
- package/src/window_selector.mm +113 -399
- package/window-selector.js +34 -112
- package/ELECTRON-INTEGRATION.md +0 -710
- package/WINDOW_SELECTOR_USAGE.md +0 -447
- package/backup/binding.gyp +0 -44
- package/backup/src/audio_capture.mm +0 -116
- package/backup/src/cursor_tracker.mm +0 -518
- package/backup/src/mac_recorder.mm +0 -829
- package/backup/src/screen_capture.h +0 -19
- package/backup/src/screen_capture.mm +0 -162
- package/backup/src/screen_capture_kit.h +0 -15
- package/backup/src/window_selector.mm +0 -1457
- package/electron-window-selector.js +0 -698
- package/node-mac-recorder-2.4.2.tgz +0 -0
- package/prebuilds/darwin-arm64/node.napi.node +0 -0
- package/test-api-compatibility.js +0 -92
- package/test-audio.js +0 -94
- package/test-comprehensive.js +0 -164
- package/test-electron-window-selector.js +0 -119
- package/test-overlay-fix.js +0 -72
- package/test-recording.js +0 -142
- package/test-sck-availability.js +0 -26
- package/test-sck-simple.js +0 -37
- package/test-sck.js +0 -56
- package/test-screencapture-overlay.js +0 -54
- package/test-simple-windows.js +0 -29
- package/test-sync.js +0 -52
- package/test-window-details.js +0 -34
- package/test-windows.js +0 -57
package/ELECTRON-INTEGRATION.md
DELETED
|
@@ -1,710 +0,0 @@
|
|
|
1
|
-
# Electron Integration Guide
|
|
2
|
-
|
|
3
|
-
Bu döküman `node-mac-recorder` paketinin Electron uygulamaları ile güvenli entegrasyonunu açıklar.
|
|
4
|
-
|
|
5
|
-
## 🔧 Sorun Çözümü
|
|
6
|
-
|
|
7
|
-
**Problem**: ScreenCaptureKit'e geçtikten sonra Electron uygulamalarında native NSWindow overlay'lar crash'e sebep oluyordu.
|
|
8
|
-
|
|
9
|
-
**Çözüm**: `ElectronWindowSelector` sınıfı otomatik olarak Electron ortamını tespit eder ve güvenli mod kullanır.
|
|
10
|
-
|
|
11
|
-
## 📋 Electron Güvenli Mod Özellikleri
|
|
12
|
-
|
|
13
|
-
### 🔍 Otomatik Tespit
|
|
14
|
-
```javascript
|
|
15
|
-
// Otomatik olarak tespit edilen environment variable'lar:
|
|
16
|
-
- process.versions.electron
|
|
17
|
-
- process.env.ELECTRON_VERSION
|
|
18
|
-
- process.env.ELECTRON_RUN_AS_NODE
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### 🚫 Native Overlay'lar Devre Dışı
|
|
22
|
-
Electron modunda aşağıdaki native işlevler güvenli modda çalışır:
|
|
23
|
-
- ✅ Window listing (güvenli)
|
|
24
|
-
- ❌ Native NSWindow overlays (devre dışı)
|
|
25
|
-
- ❌ Native recording preview overlays (devre dışı)
|
|
26
|
-
|
|
27
|
-
## 🎯 API Kullanımı
|
|
28
|
-
|
|
29
|
-
### Temel Kurulum
|
|
30
|
-
```javascript
|
|
31
|
-
const ElectronWindowSelector = require('node-mac-recorder/electron-window-selector');
|
|
32
|
-
|
|
33
|
-
const selector = new ElectronWindowSelector();
|
|
34
|
-
console.log(`Environment: ${selector.isElectron ? 'Electron' : 'Node.js'}`);
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
### Real-Time Window Detection (Electron Mode)
|
|
38
|
-
```javascript
|
|
39
|
-
// 1. Mevcut pencere listesini al
|
|
40
|
-
const windows = await selector.getAvailableWindows();
|
|
41
|
-
console.log(`Found ${windows.length} windows`);
|
|
42
|
-
|
|
43
|
-
// 2. Real-time mouse tracking başlat
|
|
44
|
-
const nativeBinding = require('./build/Release/mac_recorder.node');
|
|
45
|
-
const trackingInterval = setInterval(() => {
|
|
46
|
-
const status = nativeBinding.getWindowSelectionStatus();
|
|
47
|
-
|
|
48
|
-
if (status && status.currentWindow) {
|
|
49
|
-
const window = status.currentWindow;
|
|
50
|
-
console.log(`Window under cursor: ${window.appName} - "${window.title}"`);
|
|
51
|
-
console.log(`Position: (${window.x}, ${window.y}) Size: ${window.width}x${window.height}`);
|
|
52
|
-
|
|
53
|
-
if (window.screenId !== undefined) {
|
|
54
|
-
console.log(`Screen: ${window.screenId} (${window.screenWidth}x${window.screenHeight})`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Electron UI'da bu window'u real-time highlight et
|
|
58
|
-
highlightWindowInElectronUI(window);
|
|
59
|
-
}
|
|
60
|
-
}, 100); // 100ms polling for smooth tracking
|
|
61
|
-
|
|
62
|
-
// 3. Pencere seçimi tamamlandığında
|
|
63
|
-
function selectWindow(windowInfo) {
|
|
64
|
-
clearInterval(trackingInterval);
|
|
65
|
-
console.log('Window selected:', windowInfo);
|
|
66
|
-
|
|
67
|
-
// Recording başlat
|
|
68
|
-
startRecordingWithWindow(windowInfo);
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Screen/Display Seçimi (Electron Mode)
|
|
73
|
-
```javascript
|
|
74
|
-
// 1. Mevcut display listesini al
|
|
75
|
-
const displays = await selector.getAvailableDisplays();
|
|
76
|
-
console.log(`Found ${displays.length} displays`);
|
|
77
|
-
|
|
78
|
-
// 2. Screen seçim başlat (Electron mode'da otomatik main screen)
|
|
79
|
-
const nativeBinding = require('./build/Release/mac_recorder.node');
|
|
80
|
-
const screenResult = nativeBinding.startScreenSelection();
|
|
81
|
-
|
|
82
|
-
if (screenResult) {
|
|
83
|
-
// Screen seçim bilgisini al
|
|
84
|
-
const selectedScreen = nativeBinding.getSelectedScreenInfo();
|
|
85
|
-
|
|
86
|
-
if (selectedScreen) {
|
|
87
|
-
console.log('Screen selected:', selectedScreen);
|
|
88
|
-
console.log(`Resolution: ${selectedScreen.width}x${selectedScreen.height}`);
|
|
89
|
-
console.log(`Position: (${selectedScreen.x}, ${selectedScreen.y})`);
|
|
90
|
-
|
|
91
|
-
// Screen recording başlat
|
|
92
|
-
startScreenRecording(selectedScreen);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// 3. Manuel screen seçimi (UI ile)
|
|
97
|
-
function selectScreen(screenInfo) {
|
|
98
|
-
console.log('Screen manually selected:', screenInfo);
|
|
99
|
-
|
|
100
|
-
// Recording başlat
|
|
101
|
-
startScreenRecordingWithScreen(screenInfo);
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## 🎨 Electron UI Implementation Önerisi
|
|
106
|
-
|
|
107
|
-
### 1. Window Picker UI Component
|
|
108
|
-
|
|
109
|
-
```html
|
|
110
|
-
<!-- Electron Renderer Process -->
|
|
111
|
-
<div class="window-picker">
|
|
112
|
-
<h3>Select Window to Record</h3>
|
|
113
|
-
<div class="window-grid">
|
|
114
|
-
<!-- Her window için thumbnail ve bilgi -->
|
|
115
|
-
<div v-for="window in availableWindows"
|
|
116
|
-
:key="window.id"
|
|
117
|
-
class="window-card"
|
|
118
|
-
:class="{ selected: selectedWindow?.id === window.id }"
|
|
119
|
-
@click="selectWindow(window)">
|
|
120
|
-
|
|
121
|
-
<div class="window-thumbnail">
|
|
122
|
-
<!-- Thumbnail görseli buraya -->
|
|
123
|
-
<img :src="window.thumbnail" v-if="window.thumbnail" />
|
|
124
|
-
<div class="window-placeholder" v-else>
|
|
125
|
-
{{ window.appName?.charAt(0) || '?' }}
|
|
126
|
-
</div>
|
|
127
|
-
</div>
|
|
128
|
-
|
|
129
|
-
<div class="window-info">
|
|
130
|
-
<div class="app-name">{{ window.appName || 'Unknown App' }}</div>
|
|
131
|
-
<div class="window-title">{{ window.title || 'Untitled' }}</div>
|
|
132
|
-
<div class="window-size">{{ window.width }}×{{ window.height }}</div>
|
|
133
|
-
</div>
|
|
134
|
-
</div>
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### 2. Real-Time Window Tracking (Renderer Process)
|
|
140
|
-
```javascript
|
|
141
|
-
// renderer.js
|
|
142
|
-
const { ipcRenderer } = require('electron');
|
|
143
|
-
|
|
144
|
-
let windowSelector = null;
|
|
145
|
-
let trackingInterval = null;
|
|
146
|
-
let currentHighlightedWindow = null;
|
|
147
|
-
|
|
148
|
-
async function initializeWindowPicker() {
|
|
149
|
-
// Main process'ten window selector'ı başlat
|
|
150
|
-
const result = await ipcRenderer.invoke('init-window-selector');
|
|
151
|
-
|
|
152
|
-
if (result.success) {
|
|
153
|
-
// Mevcut windows'ları al
|
|
154
|
-
const windows = await ipcRenderer.invoke('get-available-windows');
|
|
155
|
-
displayWindowsInUI(windows);
|
|
156
|
-
|
|
157
|
-
// Real-time tracking başlat
|
|
158
|
-
startRealTimeTracking();
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function startRealTimeTracking() {
|
|
163
|
-
trackingInterval = setInterval(async () => {
|
|
164
|
-
try {
|
|
165
|
-
// Main process'ten mouse altındaki pencere bilgisini al
|
|
166
|
-
const currentWindow = await ipcRenderer.invoke('get-current-window-under-cursor');
|
|
167
|
-
|
|
168
|
-
if (currentWindow && currentWindow.id !== currentHighlightedWindow?.id) {
|
|
169
|
-
// Yeni pencere tespit edildi
|
|
170
|
-
highlightWindowInUI(currentWindow);
|
|
171
|
-
currentHighlightedWindow = currentWindow;
|
|
172
|
-
|
|
173
|
-
// UI'da bilgileri güncelle
|
|
174
|
-
updateCurrentWindowInfo(currentWindow);
|
|
175
|
-
} else if (!currentWindow && currentHighlightedWindow) {
|
|
176
|
-
// Mouse hiçbir pencere üstünde değil
|
|
177
|
-
clearWindowHighlight();
|
|
178
|
-
currentHighlightedWindow = null;
|
|
179
|
-
clearCurrentWindowInfo();
|
|
180
|
-
}
|
|
181
|
-
} catch (error) {
|
|
182
|
-
console.warn('Window tracking error:', error.message);
|
|
183
|
-
}
|
|
184
|
-
}, 100); // 100ms smooth tracking
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function highlightWindowInUI(window) {
|
|
188
|
-
// Tüm window card'ları normal hale getir
|
|
189
|
-
document.querySelectorAll('.window-card').forEach(card => {
|
|
190
|
-
card.classList.remove('hover-detected');
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
// Eşleşen window card'ı highlight et
|
|
194
|
-
const matchingCard = document.querySelector(`[data-window-id="${window.id}"]`);
|
|
195
|
-
if (matchingCard) {
|
|
196
|
-
matchingCard.classList.add('hover-detected');
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function clearWindowHighlight() {
|
|
201
|
-
document.querySelectorAll('.window-card').forEach(card => {
|
|
202
|
-
card.classList.remove('hover-detected');
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function updateCurrentWindowInfo(window) {
|
|
207
|
-
const infoDiv = document.getElementById('current-window-info');
|
|
208
|
-
if (infoDiv) {
|
|
209
|
-
infoDiv.innerHTML = `
|
|
210
|
-
<h4>Window Under Cursor</h4>
|
|
211
|
-
<p><strong>App:</strong> ${window.appName}</p>
|
|
212
|
-
<p><strong>Title:</strong> ${window.title}</p>
|
|
213
|
-
<p><strong>Size:</strong> ${window.width}×${window.height}</p>
|
|
214
|
-
<p><strong>Position:</strong> (${window.x}, ${window.y})</p>
|
|
215
|
-
${window.screenId !== undefined ?
|
|
216
|
-
`<p><strong>Screen:</strong> ${window.screenId} (${window.screenWidth}×${window.screenHeight})</p>` :
|
|
217
|
-
''}
|
|
218
|
-
`;
|
|
219
|
-
infoDiv.classList.add('visible');
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function clearCurrentWindowInfo() {
|
|
224
|
-
const infoDiv = document.getElementById('current-window-info');
|
|
225
|
-
if (infoDiv) {
|
|
226
|
-
infoDiv.classList.remove('visible');
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function displayWindowsInUI(windows) {
|
|
231
|
-
const windowGrid = document.querySelector('.window-grid');
|
|
232
|
-
windowGrid.innerHTML = '';
|
|
233
|
-
|
|
234
|
-
windows.forEach(window => {
|
|
235
|
-
const windowCard = createWindowCard(window);
|
|
236
|
-
windowGrid.appendChild(windowCard);
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function createWindowCard(window) {
|
|
241
|
-
const card = document.createElement('div');
|
|
242
|
-
card.className = 'window-card';
|
|
243
|
-
card.setAttribute('data-window-id', window.id);
|
|
244
|
-
card.innerHTML = `
|
|
245
|
-
<div class="window-thumbnail">
|
|
246
|
-
<div class="window-placeholder">${window.appName?.charAt(0) || '?'}</div>
|
|
247
|
-
</div>
|
|
248
|
-
<div class="window-info">
|
|
249
|
-
<div class="app-name">${window.appName || 'Unknown App'}</div>
|
|
250
|
-
<div class="window-title">${window.title || 'Untitled'}</div>
|
|
251
|
-
<div class="window-size">${window.width}×${window.height}</div>
|
|
252
|
-
</div>
|
|
253
|
-
`;
|
|
254
|
-
|
|
255
|
-
card.addEventListener('click', () => selectWindow(window));
|
|
256
|
-
return card;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
function selectWindow(window) {
|
|
260
|
-
// Tracking'i durdur
|
|
261
|
-
if (trackingInterval) {
|
|
262
|
-
clearInterval(trackingInterval);
|
|
263
|
-
trackingInterval = null;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// UI'da seçimi görsel olarak göster
|
|
267
|
-
document.querySelectorAll('.window-card').forEach(card => {
|
|
268
|
-
card.classList.remove('selected', 'hover-detected');
|
|
269
|
-
});
|
|
270
|
-
event.target.closest('.window-card').classList.add('selected');
|
|
271
|
-
|
|
272
|
-
// Main process'e seçimi bildir
|
|
273
|
-
ipcRenderer.invoke('window-selected', window);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Cleanup function
|
|
277
|
-
window.addEventListener('beforeunload', () => {
|
|
278
|
-
if (trackingInterval) {
|
|
279
|
-
clearInterval(trackingInterval);
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
### 3. Enhanced Main Process Handler
|
|
285
|
-
```javascript
|
|
286
|
-
// main.js
|
|
287
|
-
const { ipcMain } = require('electron');
|
|
288
|
-
const ElectronWindowSelector = require('node-mac-recorder/electron-window-selector');
|
|
289
|
-
|
|
290
|
-
let windowSelector = null;
|
|
291
|
-
let nativeBinding = null;
|
|
292
|
-
|
|
293
|
-
ipcMain.handle('init-window-selector', async () => {
|
|
294
|
-
try {
|
|
295
|
-
windowSelector = new ElectronWindowSelector();
|
|
296
|
-
|
|
297
|
-
// Native binding'i yükle (real-time tracking için)
|
|
298
|
-
try {
|
|
299
|
-
nativeBinding = require('./build/Release/mac_recorder.node');
|
|
300
|
-
} catch (error) {
|
|
301
|
-
console.warn('Native binding yüklenemedi:', error.message);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
return { success: true };
|
|
305
|
-
} catch (error) {
|
|
306
|
-
return { success: false, error: error.message };
|
|
307
|
-
}
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
ipcMain.handle('get-available-windows', async () => {
|
|
311
|
-
if (!windowSelector) return [];
|
|
312
|
-
return await windowSelector.getAvailableWindows();
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
ipcMain.handle('get-available-displays', async () => {
|
|
316
|
-
if (!windowSelector) return [];
|
|
317
|
-
return await windowSelector.getAvailableDisplays();
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
// Real-time window tracking için yeni handler
|
|
321
|
-
ipcMain.handle('get-current-window-under-cursor', async () => {
|
|
322
|
-
if (!nativeBinding) return null;
|
|
323
|
-
|
|
324
|
-
try {
|
|
325
|
-
const status = nativeBinding.getWindowSelectionStatus();
|
|
326
|
-
return status?.currentWindow || null;
|
|
327
|
-
} catch (error) {
|
|
328
|
-
console.warn('Window status alınamadı:', error.message);
|
|
329
|
-
return null;
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
ipcMain.handle('window-selected', async (event, windowInfo) => {
|
|
334
|
-
console.log('Window selected in Electron UI:', windowInfo);
|
|
335
|
-
console.log(` - App: ${windowInfo.appName}`);
|
|
336
|
-
console.log(` - Title: ${windowInfo.title}`);
|
|
337
|
-
console.log(` - Size: ${windowInfo.width}×${windowInfo.height}`);
|
|
338
|
-
console.log(` - Position: (${windowInfo.x}, ${windowInfo.y})`);
|
|
339
|
-
|
|
340
|
-
if (windowInfo.screenId !== undefined) {
|
|
341
|
-
console.log(` - Screen: ${windowInfo.screenId} (${windowInfo.screenWidth}×${windowInfo.screenHeight})`);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// Recording başlatılabilir
|
|
345
|
-
const MacRecorder = require('node-mac-recorder');
|
|
346
|
-
const recorder = new MacRecorder();
|
|
347
|
-
|
|
348
|
-
try {
|
|
349
|
-
// Window recording başlat
|
|
350
|
-
await recorder.startRecording('./output.mov', {
|
|
351
|
-
windowId: windowInfo.id,
|
|
352
|
-
// Screen coordination
|
|
353
|
-
x: windowInfo.x,
|
|
354
|
-
y: windowInfo.y,
|
|
355
|
-
width: windowInfo.width,
|
|
356
|
-
height: windowInfo.height,
|
|
357
|
-
// Diğer options
|
|
358
|
-
fps: 30,
|
|
359
|
-
audioEnabled: true
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
return {
|
|
363
|
-
success: true,
|
|
364
|
-
message: 'Recording started successfully',
|
|
365
|
-
windowInfo: windowInfo
|
|
366
|
-
};
|
|
367
|
-
} catch (error) {
|
|
368
|
-
return {
|
|
369
|
-
success: false,
|
|
370
|
-
error: error.message
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
// Screen recording handler
|
|
376
|
-
ipcMain.handle('screen-selected', async (event, screenInfo) => {
|
|
377
|
-
console.log('Screen selected in Electron UI:', screenInfo);
|
|
378
|
-
|
|
379
|
-
const MacRecorder = require('node-mac-recorder');
|
|
380
|
-
const recorder = new MacRecorder();
|
|
381
|
-
|
|
382
|
-
try {
|
|
383
|
-
// Screen recording başlat
|
|
384
|
-
await recorder.startRecording('./screen-output.mov', {
|
|
385
|
-
// Screen mode
|
|
386
|
-
screenId: screenInfo.id,
|
|
387
|
-
x: screenInfo.x,
|
|
388
|
-
y: screenInfo.y,
|
|
389
|
-
width: screenInfo.width,
|
|
390
|
-
height: screenInfo.height,
|
|
391
|
-
fps: 30,
|
|
392
|
-
audioEnabled: true
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
return {
|
|
396
|
-
success: true,
|
|
397
|
-
message: 'Screen recording started',
|
|
398
|
-
screenInfo: screenInfo
|
|
399
|
-
};
|
|
400
|
-
} catch (error) {
|
|
401
|
-
return {
|
|
402
|
-
success: false,
|
|
403
|
-
error: error.message
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
// Recording control handlers
|
|
409
|
-
ipcMain.handle('stop-recording', async () => {
|
|
410
|
-
// Aktif recorder instance'ı durdur
|
|
411
|
-
// Bu implementation'a recorder management eklenmeli
|
|
412
|
-
return { success: true, message: 'Recording stopped' };
|
|
413
|
-
});
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
## 🎬 Recording Preview (Electron Mode)
|
|
417
|
-
|
|
418
|
-
Electron modunda native preview'lar çalışmaz. Bunun yerine Electron UI'da preview gösterin:
|
|
419
|
-
|
|
420
|
-
```javascript
|
|
421
|
-
// Recording preview'ı Electron UI'da göster
|
|
422
|
-
function showRecordingPreview(windowInfo) {
|
|
423
|
-
// Electron window'da overlay div oluştur
|
|
424
|
-
const overlay = document.createElement('div');
|
|
425
|
-
overlay.className = 'recording-preview-overlay';
|
|
426
|
-
overlay.style.cssText = `
|
|
427
|
-
position: fixed;
|
|
428
|
-
top: 0;
|
|
429
|
-
left: 0;
|
|
430
|
-
right: 0;
|
|
431
|
-
bottom: 0;
|
|
432
|
-
background: rgba(0, 0, 0, 0.5);
|
|
433
|
-
z-index: 9999;
|
|
434
|
-
display: flex;
|
|
435
|
-
align-items: center;
|
|
436
|
-
justify-content: center;
|
|
437
|
-
`;
|
|
438
|
-
|
|
439
|
-
overlay.innerHTML = `
|
|
440
|
-
<div class="preview-info">
|
|
441
|
-
<h3>Recording Preview</h3>
|
|
442
|
-
<p>Recording: ${windowInfo.appName} - ${windowInfo.title}</p>
|
|
443
|
-
<p>Area: ${windowInfo.width}×${windowInfo.height}</p>
|
|
444
|
-
<button id="start-recording">Start Recording</button>
|
|
445
|
-
<button id="cancel-preview">Cancel</button>
|
|
446
|
-
</div>
|
|
447
|
-
`;
|
|
448
|
-
|
|
449
|
-
document.body.appendChild(overlay);
|
|
450
|
-
}
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
## 🎨 Enhanced CSS Styling (Real-Time Tracking)
|
|
454
|
-
```css
|
|
455
|
-
.window-picker {
|
|
456
|
-
padding: 20px;
|
|
457
|
-
max-height: 500px;
|
|
458
|
-
overflow-y: auto;
|
|
459
|
-
position: relative;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
.window-grid {
|
|
463
|
-
display: grid;
|
|
464
|
-
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
465
|
-
gap: 15px;
|
|
466
|
-
margin-top: 15px;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
.window-card {
|
|
470
|
-
border: 2px solid #e1e1e1;
|
|
471
|
-
border-radius: 8px;
|
|
472
|
-
padding: 10px;
|
|
473
|
-
cursor: pointer;
|
|
474
|
-
transition: all 0.2s;
|
|
475
|
-
position: relative;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
.window-card:hover {
|
|
479
|
-
border-color: #007acc;
|
|
480
|
-
background-color: #f0f8ff;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
.window-card.selected {
|
|
484
|
-
border-color: #007acc;
|
|
485
|
-
background-color: #e6f3ff;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/* Real-time hover detection styling */
|
|
489
|
-
.window-card.hover-detected {
|
|
490
|
-
border-color: #ff6b35 !important;
|
|
491
|
-
background-color: #fff3f0 !important;
|
|
492
|
-
box-shadow: 0 4px 12px rgba(255, 107, 53, 0.3);
|
|
493
|
-
transform: translateY(-2px);
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
.window-card.hover-detected::before {
|
|
497
|
-
content: "🎯 CURSOR HERE";
|
|
498
|
-
position: absolute;
|
|
499
|
-
top: -10px;
|
|
500
|
-
right: 5px;
|
|
501
|
-
background: #ff6b35;
|
|
502
|
-
color: white;
|
|
503
|
-
padding: 2px 6px;
|
|
504
|
-
border-radius: 4px;
|
|
505
|
-
font-size: 10px;
|
|
506
|
-
font-weight: bold;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
.window-thumbnail {
|
|
510
|
-
height: 80px;
|
|
511
|
-
background: #f5f5f5;
|
|
512
|
-
border-radius: 4px;
|
|
513
|
-
display: flex;
|
|
514
|
-
align-items: center;
|
|
515
|
-
justify-content: center;
|
|
516
|
-
margin-bottom: 8px;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
.window-placeholder {
|
|
520
|
-
font-size: 24px;
|
|
521
|
-
font-weight: bold;
|
|
522
|
-
color: #666;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
.window-info {
|
|
526
|
-
text-align: center;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
.app-name {
|
|
530
|
-
font-weight: bold;
|
|
531
|
-
color: #333;
|
|
532
|
-
margin-bottom: 2px;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
.window-title {
|
|
536
|
-
color: #666;
|
|
537
|
-
font-size: 12px;
|
|
538
|
-
margin-bottom: 2px;
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
.window-size {
|
|
542
|
-
color: #999;
|
|
543
|
-
font-size: 11px;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
/* Real-time info panel */
|
|
547
|
-
#current-window-info {
|
|
548
|
-
position: fixed;
|
|
549
|
-
top: 20px;
|
|
550
|
-
right: 20px;
|
|
551
|
-
background: rgba(0, 0, 0, 0.9);
|
|
552
|
-
color: white;
|
|
553
|
-
padding: 15px;
|
|
554
|
-
border-radius: 8px;
|
|
555
|
-
min-width: 250px;
|
|
556
|
-
opacity: 0;
|
|
557
|
-
transform: translateX(300px);
|
|
558
|
-
transition: all 0.3s ease;
|
|
559
|
-
z-index: 1000;
|
|
560
|
-
font-family: 'Monaco', monospace;
|
|
561
|
-
font-size: 12px;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
#current-window-info.visible {
|
|
565
|
-
opacity: 1;
|
|
566
|
-
transform: translateX(0);
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
#current-window-info h4 {
|
|
570
|
-
margin: 0 0 10px 0;
|
|
571
|
-
color: #ff6b35;
|
|
572
|
-
font-size: 14px;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
#current-window-info p {
|
|
576
|
-
margin: 4px 0;
|
|
577
|
-
line-height: 1.4;
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
#current-window-info strong {
|
|
581
|
-
color: #fff;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
/* Animation for smooth transitions */
|
|
585
|
-
.window-card {
|
|
586
|
-
will-change: transform, box-shadow, border-color;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
@keyframes pulseHover {
|
|
590
|
-
0% { transform: scale(1) translateY(-2px); }
|
|
591
|
-
50% { transform: scale(1.02) translateY(-3px); }
|
|
592
|
-
100% { transform: scale(1) translateY(-2px); }
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
.window-card.hover-detected {
|
|
596
|
-
animation: pulseHover 2s infinite;
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
/* Status indicator */
|
|
600
|
-
.tracking-status {
|
|
601
|
-
position: absolute;
|
|
602
|
-
top: 10px;
|
|
603
|
-
left: 20px;
|
|
604
|
-
background: #4CAF50;
|
|
605
|
-
color: white;
|
|
606
|
-
padding: 5px 10px;
|
|
607
|
-
border-radius: 15px;
|
|
608
|
-
font-size: 12px;
|
|
609
|
-
font-weight: bold;
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
.tracking-status::before {
|
|
613
|
-
content: "🔴 ";
|
|
614
|
-
animation: blink 1s infinite;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
@keyframes blink {
|
|
618
|
-
0%, 50% { opacity: 1; }
|
|
619
|
-
51%, 100% { opacity: 0; }
|
|
620
|
-
}
|
|
621
|
-
```
|
|
622
|
-
|
|
623
|
-
## ✨ Yeni Real-Time Tracking Özellikleri
|
|
624
|
-
|
|
625
|
-
### 🎯 Anlık Window Tespit
|
|
626
|
-
- **100ms polling** ile smooth mouse tracking
|
|
627
|
-
- Mouse hangi pencere üstüne giderse **otomatik highlight**
|
|
628
|
-
- **Screen detection** - pencere hangi ekranda, otomatik tespit
|
|
629
|
-
- **Koordinat bilgisi** - x, y, width, height gerçek zamanlı
|
|
630
|
-
|
|
631
|
-
### 🔥 UI Features
|
|
632
|
-
- `hover-detected` class ile anlık görsel feedback
|
|
633
|
-
- Real-time info panel (sağ üst köşe)
|
|
634
|
-
- Pulse animation effect
|
|
635
|
-
- "🎯 CURSOR HERE" indicator
|
|
636
|
-
|
|
637
|
-
### 🖥️ Multi-Screen Support
|
|
638
|
-
- Pencere hangi screen'de otomatik tespit
|
|
639
|
-
- Screen koordinatları ve boyutları dahil
|
|
640
|
-
- Cross-screen window tracking
|
|
641
|
-
|
|
642
|
-
## ⚠️ Önemli Notlar
|
|
643
|
-
|
|
644
|
-
### 🔧 Teknik Gereksinimler
|
|
645
|
-
1. **Native Module**: Real-time tracking için native binding gerekli
|
|
646
|
-
2. **macOS Permissions**: Screen Recording ve Accessibility izinleri
|
|
647
|
-
3. **Electron Environment**: `ELECTRON_VERSION` env variable otomatik tespit
|
|
648
|
-
4. **Performance**: 100ms polling interval (ayarlanabilir)
|
|
649
|
-
|
|
650
|
-
### 🛠️ Implementation Notes
|
|
651
|
-
1. **IPC Communication**: Main ↔ Renderer process real-time data exchange
|
|
652
|
-
2. **Memory Management**: Interval cleanup önemli
|
|
653
|
-
3. **Error Handling**: Native binding yoksa graceful fallback
|
|
654
|
-
4. **UI Responsiveness**: CSS transitions ile smooth UX
|
|
655
|
-
|
|
656
|
-
### 🚨 Troubleshooting
|
|
657
|
-
- **Native binding yüklenemezse**: `npm run build` ile tekrar derle
|
|
658
|
-
- **Permission hatası**: System Preferences → Security & Privacy
|
|
659
|
-
- **Tracking çalışmıyorsa**: `ELECTRON_VERSION` environment variable kontrol et
|
|
660
|
-
- **UI update yavaşsa**: Polling interval'ı artır (100ms → 200ms)
|
|
661
|
-
|
|
662
|
-
## 🚀 Sonraki Adımlar
|
|
663
|
-
|
|
664
|
-
### Phase 1: Core Enhancement
|
|
665
|
-
1. ✅ **Real-time window tracking** - TAMAMLANDI
|
|
666
|
-
2. ✅ **Screen detection accuracy** - TAMAMLANDI
|
|
667
|
-
3. ✅ **Electron compatibility** - TAMAMLANDI
|
|
668
|
-
4. 🔄 Thumbnail generation implementasyonu
|
|
669
|
-
|
|
670
|
-
### Phase 2: Advanced Features
|
|
671
|
-
5. 📋 Window list real-time updates
|
|
672
|
-
6. 🖥️ Multiple display UI enhancement
|
|
673
|
-
7. 📹 Recording progress indicator
|
|
674
|
-
8. ✂️ Custom recording area selection
|
|
675
|
-
9. 🎨 Window preview thumbnails
|
|
676
|
-
|
|
677
|
-
### Phase 3: Performance & UX
|
|
678
|
-
10. ⚡ Performance optimization
|
|
679
|
-
11. 🎭 Advanced animations
|
|
680
|
-
12. 📱 Responsive design improvements
|
|
681
|
-
13. 🔧 Settings panel
|
|
682
|
-
|
|
683
|
-
## 📞 Test Komutları
|
|
684
|
-
|
|
685
|
-
```bash
|
|
686
|
-
# Fixed overlay functionality test
|
|
687
|
-
node test-overlay-fix.js
|
|
688
|
-
|
|
689
|
-
# Electron mode test
|
|
690
|
-
ELECTRON_VERSION=25.0.0 node test-overlay-fix.js
|
|
691
|
-
|
|
692
|
-
# Build native module
|
|
693
|
-
npm run build
|
|
694
|
-
|
|
695
|
-
# Full integration test
|
|
696
|
-
node test-electron-window-selector.js
|
|
697
|
-
```
|
|
698
|
-
|
|
699
|
-
## 🎉 Sonuç
|
|
700
|
-
|
|
701
|
-
Bu güncellenmiş implementasyon ile:
|
|
702
|
-
|
|
703
|
-
✅ **Mouse tracking** gerçek zamanlı çalışıyor
|
|
704
|
-
✅ **Window detection** hassas ve hızlı
|
|
705
|
-
✅ **Screen coordination** doğru hesaplanıyor
|
|
706
|
-
✅ **Electron integration** sorunsuz çalışıyor
|
|
707
|
-
✅ **Multi-display support** tam uyumlu
|
|
708
|
-
✅ **Real-time UI feedback** kullanıcı dostu
|
|
709
|
-
|
|
710
|
-
Electron uygulamanızda artık native overlay benzeri deneyim sunabilir, kullanıcı mouse'u hareket ettirdikçe hangi pencere üstünde olduğunu görebilir ve tek tıkla recording başlatabilirsiniz!
|