node-mac-recorder 1.2.11 → 1.4.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.
- package/.claude/settings.local.json +4 -1
- package/WINDOW_SELECTOR_README.md +461 -0
- package/auto-front-demo.js +71 -0
- package/binding.gyp +2 -1
- package/bring-to-front-test.js +159 -0
- package/debug-window-selector.js +178 -0
- package/enhanced-window-selector.js +202 -0
- package/examples/integration-example.js +228 -0
- package/examples/window-selector-example.js +254 -0
- package/index.js +3 -0
- package/package.json +4 -2
- package/simple-test.js +38 -0
- package/src/mac_recorder.mm +6 -0
- package/src/window_selector.mm +640 -0
- package/window-selector-test.js +160 -0
- package/window-selector.js +291 -0
- package/working-example.js +94 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
# Window Selector
|
|
2
|
+
|
|
3
|
+
**macOS Window Selection Tool with Real-time Visual Overlay**
|
|
4
|
+
|
|
5
|
+
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.
|
|
6
|
+
|
|
7
|
+
## ✨ Özellikler
|
|
8
|
+
|
|
9
|
+
- **Real-time Window Detection**: İmleç hangi pencereye gelirse otomatik olarak tespit eder
|
|
10
|
+
- **Visual Overlay**: Seçilebilir pencereleri mavi transparant kapsayıcı ile highlight eder
|
|
11
|
+
- **Interactive Selection**: Merkeze yerleştirilen "Select Window" butonu ile kolay seçim
|
|
12
|
+
- **Multi-display Support**: Çoklu ekran kurulumlarında çalışır
|
|
13
|
+
- **Detailed Window Info**: Pencere pozisyonu, boyutu ve hangi ekranda olduğunu döndürür
|
|
14
|
+
- **Event-driven API**: Pencere hover, seçim ve hata durumları için event'ler
|
|
15
|
+
- **Window Focus Control**: Detect edilen pencereyi otomatik olarak en öne getirir
|
|
16
|
+
- **Auto Bring-to-Front**: Cursor hangi pencereye gelirse otomatik focus yapar
|
|
17
|
+
- **Permission Management**: macOS izin kontrolü ve yönetimi
|
|
18
|
+
|
|
19
|
+
## 🚀 Kurulum
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Ana proje dizininde
|
|
23
|
+
npm install
|
|
24
|
+
|
|
25
|
+
# Native modülü build edin
|
|
26
|
+
npm run build
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 📋 Sistem Gereksinimleri
|
|
30
|
+
|
|
31
|
+
- **macOS 10.15+** (Catalina veya üzeri)
|
|
32
|
+
- **Node.js 14+**
|
|
33
|
+
- **Xcode Command Line Tools**
|
|
34
|
+
- **System Permissions**:
|
|
35
|
+
- Screen Recording permission
|
|
36
|
+
- Accessibility permission
|
|
37
|
+
|
|
38
|
+
## 🔐 İzinler
|
|
39
|
+
|
|
40
|
+
İlk kullanımda macOS aşağıdaki izinleri isteyecektir:
|
|
41
|
+
|
|
42
|
+
1. **System Preferences > Security & Privacy > Privacy > Screen Recording**
|
|
43
|
+
- Terminal veya kullandığınız IDE'yi (VSCode, WebStorm, vb.) etkinleştirin
|
|
44
|
+
|
|
45
|
+
2. **System Preferences > Security & Privacy > Privacy > Accessibility**
|
|
46
|
+
- Terminal veya kullandığınız IDE'yi etkinleştirin
|
|
47
|
+
|
|
48
|
+
## 🎯 Temel Kullanım
|
|
49
|
+
|
|
50
|
+
### Basit Pencere Seçimi
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
const WindowSelector = require('./window-selector');
|
|
54
|
+
|
|
55
|
+
async function selectWindow() {
|
|
56
|
+
const selector = new WindowSelector();
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
console.log('Bir pencere seçin...');
|
|
60
|
+
const selectedWindow = await selector.selectWindow();
|
|
61
|
+
|
|
62
|
+
console.log('Seçilen pencere:', {
|
|
63
|
+
title: selectedWindow.title,
|
|
64
|
+
app: selectedWindow.appName,
|
|
65
|
+
position: `(${selectedWindow.x}, ${selectedWindow.y})`,
|
|
66
|
+
size: `${selectedWindow.width}x${selectedWindow.height}`,
|
|
67
|
+
screen: selectedWindow.screenId
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return selectedWindow;
|
|
71
|
+
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error('Hata:', error.message);
|
|
74
|
+
} finally {
|
|
75
|
+
await selector.cleanup();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
selectWindow();
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Manuel Kontrol
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
const WindowSelector = require('./window-selector');
|
|
86
|
+
|
|
87
|
+
async function manualSelection() {
|
|
88
|
+
const selector = new WindowSelector();
|
|
89
|
+
|
|
90
|
+
// Event listener'lar
|
|
91
|
+
selector.on('windowEntered', (window) => {
|
|
92
|
+
console.log(`Pencere üstünde: ${window.title} (${window.appName})`);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
selector.on('windowSelected', (window) => {
|
|
96
|
+
console.log(`Seçildi: ${window.title}`);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Seçimi başlat
|
|
100
|
+
await selector.startSelection();
|
|
101
|
+
|
|
102
|
+
// Kullanıcı seçim yapana kadar bekle
|
|
103
|
+
// Seçim tamamlandığında 'windowSelected' event'i tetiklenir
|
|
104
|
+
|
|
105
|
+
// Seçimi durdurmak için:
|
|
106
|
+
// await selector.stopSelection();
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 📚 API Reference
|
|
111
|
+
|
|
112
|
+
### WindowSelector Class
|
|
113
|
+
|
|
114
|
+
#### Constructor
|
|
115
|
+
```javascript
|
|
116
|
+
const selector = new WindowSelector();
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### Methods
|
|
120
|
+
|
|
121
|
+
##### `async selectWindow()`
|
|
122
|
+
Promise tabanlı pencere seçimi. Kullanıcı bir pencere seçene kadar bekler.
|
|
123
|
+
|
|
124
|
+
**Returns:** `Promise<WindowInfo>`
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
const window = await selector.selectWindow();
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
##### `async startSelection()`
|
|
131
|
+
Pencere seçim modunu başlatır.
|
|
132
|
+
|
|
133
|
+
**Returns:** `Promise<boolean>`
|
|
134
|
+
|
|
135
|
+
##### `async stopSelection()`
|
|
136
|
+
Pencere seçim modunu durdurur.
|
|
137
|
+
|
|
138
|
+
**Returns:** `Promise<boolean>`
|
|
139
|
+
|
|
140
|
+
##### `getSelectedWindow()`
|
|
141
|
+
Son seçilen pencere bilgisini döndürür.
|
|
142
|
+
|
|
143
|
+
**Returns:** `WindowInfo | null`
|
|
144
|
+
|
|
145
|
+
##### `getStatus()`
|
|
146
|
+
Seçici durumunu döndürür.
|
|
147
|
+
|
|
148
|
+
**Returns:** `SelectionStatus`
|
|
149
|
+
|
|
150
|
+
##### `async checkPermissions()`
|
|
151
|
+
macOS izinlerini kontrol eder.
|
|
152
|
+
|
|
153
|
+
**Returns:** `Promise<PermissionStatus>`
|
|
154
|
+
|
|
155
|
+
##### `async bringWindowToFront(windowId)`
|
|
156
|
+
Belirtilen pencereyi en öne getirir (focus yapar).
|
|
157
|
+
|
|
158
|
+
**Parameters:**
|
|
159
|
+
- `windowId` (number) - Window ID
|
|
160
|
+
|
|
161
|
+
**Returns:** `Promise<boolean>` - Başarı/başarısızlık
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
const success = await selector.bringWindowToFront(windowInfo.id);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
##### `setBringToFrontEnabled(enabled)`
|
|
168
|
+
Otomatik pencere en öne getirme özelliğini aktif/pasif yapar.
|
|
169
|
+
|
|
170
|
+
**Parameters:**
|
|
171
|
+
- `enabled` (boolean) - Enable/disable
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
selector.setBringToFrontEnabled(true); // Auto mode ON
|
|
175
|
+
selector.setBringToFrontEnabled(false); // Auto mode OFF
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
##### `async cleanup()`
|
|
179
|
+
Tüm kaynakları temizler ve seçimi durdurur.
|
|
180
|
+
|
|
181
|
+
#### Events
|
|
182
|
+
|
|
183
|
+
##### `selectionStarted`
|
|
184
|
+
Seçim modu başladığında tetiklenir.
|
|
185
|
+
|
|
186
|
+
```javascript
|
|
187
|
+
selector.on('selectionStarted', () => {
|
|
188
|
+
console.log('Seçim başladı');
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
##### `windowEntered`
|
|
193
|
+
İmleç bir pencereye geldiğinde tetiklenir.
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
selector.on('windowEntered', (windowInfo) => {
|
|
197
|
+
console.log(`Pencere: ${windowInfo.title}`);
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
##### `windowLeft`
|
|
202
|
+
İmleç bir pencereden ayrıldığında tetiklenir.
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
selector.on('windowLeft', (windowInfo) => {
|
|
206
|
+
console.log(`Ayrıldı: ${windowInfo.title}`);
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
##### `windowSelected`
|
|
211
|
+
Bir pencere seçildiğinde tetiklenir.
|
|
212
|
+
|
|
213
|
+
```javascript
|
|
214
|
+
selector.on('windowSelected', (windowInfo) => {
|
|
215
|
+
console.log('Seçilen pencere:', windowInfo);
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
##### `selectionStopped`
|
|
220
|
+
Seçim modu durduğunda tetiklenir.
|
|
221
|
+
|
|
222
|
+
##### `error`
|
|
223
|
+
Bir hata oluştuğunda tetiklenir.
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
selector.on('error', (error) => {
|
|
227
|
+
console.error('Hata:', error.message);
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## 📊 Data Types
|
|
232
|
+
|
|
233
|
+
### WindowInfo
|
|
234
|
+
```javascript
|
|
235
|
+
{
|
|
236
|
+
id: number, // Pencere ID'si
|
|
237
|
+
title: string, // Pencere başlığı
|
|
238
|
+
appName: string, // Uygulama adı
|
|
239
|
+
x: number, // Global X pozisyonu
|
|
240
|
+
y: number, // Global Y pozisyonu
|
|
241
|
+
width: number, // Pencere genişliği
|
|
242
|
+
height: number, // Pencere yüksekliği
|
|
243
|
+
screenId: number, // Hangi ekranda olduğu
|
|
244
|
+
screenX: number, // Ekranın X pozisyonu
|
|
245
|
+
screenY: number, // Ekranın Y pozisyonu
|
|
246
|
+
screenWidth: number, // Ekran genişliği
|
|
247
|
+
screenHeight: number // Ekran yüksekliği
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### SelectionStatus
|
|
252
|
+
```javascript
|
|
253
|
+
{
|
|
254
|
+
isSelecting: boolean, // Seçim modunda mı?
|
|
255
|
+
hasSelectedWindow: boolean, // Seçilmiş pencere var mı?
|
|
256
|
+
selectedWindow: WindowInfo | null,
|
|
257
|
+
nativeStatus: object // Native durum bilgisi
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### PermissionStatus
|
|
262
|
+
```javascript
|
|
263
|
+
{
|
|
264
|
+
screenRecording: boolean, // Ekran kaydı izni
|
|
265
|
+
accessibility: boolean, // Erişilebilirlik izni
|
|
266
|
+
microphone: boolean // Mikrofon izni
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## 🎮 Test Etme
|
|
271
|
+
|
|
272
|
+
### Test Dosyasını Çalıştır
|
|
273
|
+
```bash
|
|
274
|
+
# Interaktif test
|
|
275
|
+
node window-selector-test.js
|
|
276
|
+
|
|
277
|
+
# API test modu
|
|
278
|
+
node window-selector-test.js --api-test
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Örnekleri Çalıştır
|
|
282
|
+
```bash
|
|
283
|
+
# Basit örnek
|
|
284
|
+
node examples/window-selector-example.js
|
|
285
|
+
|
|
286
|
+
# Gelişmiş örnek (event'lerle)
|
|
287
|
+
node examples/window-selector-example.js --advanced
|
|
288
|
+
|
|
289
|
+
# Çoklu seçim
|
|
290
|
+
node examples/window-selector-example.js --multiple
|
|
291
|
+
|
|
292
|
+
# Detaylı analiz
|
|
293
|
+
node examples/window-selector-example.js --analysis
|
|
294
|
+
|
|
295
|
+
# Yardım
|
|
296
|
+
node examples/window-selector-example.js --help
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## ⚡ Nasıl Çalışır?
|
|
300
|
+
|
|
301
|
+
1. **Window Detection**: macOS `CGWindowListCopyWindowInfo` API'si ile açık pencereleri tespit eder
|
|
302
|
+
2. **Cursor Tracking**: Real-time olarak imleç pozisyonunu takip eder
|
|
303
|
+
3. **Overlay Rendering**: NSWindow ile transparant overlay penceresi oluşturur
|
|
304
|
+
4. **Hit Testing**: İmlecin hangi pencere üstünde olduğunu hesaplar
|
|
305
|
+
5. **Visual Feedback**: Pencereyi highlight eden mavi kapsayıcı çizer
|
|
306
|
+
6. **User Interaction**: Merkeze yerleştirilen button ile seçim yapar
|
|
307
|
+
7. **Data Collection**: Seçilen pencerenin tüm bilgilerini toplar
|
|
308
|
+
|
|
309
|
+
## 🔧 Troubleshooting
|
|
310
|
+
|
|
311
|
+
### Build Hataları
|
|
312
|
+
```bash
|
|
313
|
+
# Xcode Command Line Tools'u yükle
|
|
314
|
+
xcode-select --install
|
|
315
|
+
|
|
316
|
+
# Node-gyp'i yeniden build et
|
|
317
|
+
npm run clean
|
|
318
|
+
npm run build
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### İzin Hataları
|
|
322
|
+
1. **System Preferences > Security & Privacy > Privacy** bölümüne git
|
|
323
|
+
2. **Screen Recording** ve **Accessibility** sekmelerinde Terminal'i etkinleştir
|
|
324
|
+
3. Uygulamayı yeniden başlat
|
|
325
|
+
|
|
326
|
+
### Runtime Hataları
|
|
327
|
+
```javascript
|
|
328
|
+
// İzinleri kontrol et
|
|
329
|
+
const permissions = await selector.checkPermissions();
|
|
330
|
+
if (!permissions.screenRecording) {
|
|
331
|
+
console.log('Screen recording permission required');
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## 🌟 Gelişmiş Örnekler
|
|
336
|
+
|
|
337
|
+
### Auto Bring-to-Front (Otomatik Focus)
|
|
338
|
+
```javascript
|
|
339
|
+
const WindowSelector = require('./window-selector');
|
|
340
|
+
|
|
341
|
+
async function autoBringToFront() {
|
|
342
|
+
const selector = new WindowSelector();
|
|
343
|
+
|
|
344
|
+
// Otomatik focus modunu aktif et
|
|
345
|
+
selector.setBringToFrontEnabled(true);
|
|
346
|
+
|
|
347
|
+
selector.on('windowEntered', (window) => {
|
|
348
|
+
console.log(`🔝 Auto-focused: ${window.appName} - "${window.title}"`);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
await selector.startSelection();
|
|
352
|
+
console.log('🖱️ Move cursor over windows - they will come to front automatically!');
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Manuel Window Focus
|
|
357
|
+
```javascript
|
|
358
|
+
const WindowSelector = require('./window-selector');
|
|
359
|
+
|
|
360
|
+
async function manualFocus() {
|
|
361
|
+
const selector = new WindowSelector();
|
|
362
|
+
|
|
363
|
+
selector.on('windowEntered', async (window) => {
|
|
364
|
+
console.log(`Found: ${window.appName} - "${window.title}"`);
|
|
365
|
+
|
|
366
|
+
// Manuel olarak pencereyi en öne getir
|
|
367
|
+
const success = await selector.bringWindowToFront(window.id);
|
|
368
|
+
if (success) {
|
|
369
|
+
console.log('✅ Window brought to front!');
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
await selector.startSelection();
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Otomatik Pencere Kaydı
|
|
378
|
+
```javascript
|
|
379
|
+
const WindowSelector = require('./window-selector');
|
|
380
|
+
const MacRecorder = require('./index');
|
|
381
|
+
|
|
382
|
+
async function recordSelectedWindow() {
|
|
383
|
+
const selector = new WindowSelector();
|
|
384
|
+
const recorder = new MacRecorder();
|
|
385
|
+
|
|
386
|
+
try {
|
|
387
|
+
// Pencere seç
|
|
388
|
+
const window = await selector.selectWindow();
|
|
389
|
+
console.log(`Recording: ${window.title}`);
|
|
390
|
+
|
|
391
|
+
// Seçilen pencereyi kaydet
|
|
392
|
+
const outputPath = `./recordings/${window.appName}-${Date.now()}.mov`;
|
|
393
|
+
await recorder.startRecording(outputPath, {
|
|
394
|
+
windowId: window.id,
|
|
395
|
+
captureCursor: true,
|
|
396
|
+
includeMicrophone: true
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// 10 saniye kaydet
|
|
400
|
+
setTimeout(async () => {
|
|
401
|
+
await recorder.stopRecording();
|
|
402
|
+
console.log(`Recording saved: ${outputPath}`);
|
|
403
|
+
}, 10000);
|
|
404
|
+
|
|
405
|
+
} finally {
|
|
406
|
+
await selector.cleanup();
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Pencere Monitoring
|
|
412
|
+
```javascript
|
|
413
|
+
const WindowSelector = require('./window-selector');
|
|
414
|
+
|
|
415
|
+
async function monitorWindowChanges() {
|
|
416
|
+
const selector = new WindowSelector();
|
|
417
|
+
const visitedWindows = new Set();
|
|
418
|
+
|
|
419
|
+
selector.on('windowEntered', (window) => {
|
|
420
|
+
const key = `${window.appName}-${window.title}`;
|
|
421
|
+
if (!visitedWindows.has(key)) {
|
|
422
|
+
visitedWindows.add(key);
|
|
423
|
+
console.log(`Yeni pencere keşfedildi: ${window.title} (${window.appName})`);
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
await selector.startSelection();
|
|
428
|
+
|
|
429
|
+
// İptal etmek için Ctrl+C
|
|
430
|
+
process.on('SIGINT', async () => {
|
|
431
|
+
console.log(`\nToplam keşfedilen pencere: ${visitedWindows.size}`);
|
|
432
|
+
await selector.cleanup();
|
|
433
|
+
process.exit(0);
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
## 📄 Lisans
|
|
439
|
+
|
|
440
|
+
Bu modül ana projenin lisansı altındadır.
|
|
441
|
+
|
|
442
|
+
## 🤝 Katkıda Bulunma
|
|
443
|
+
|
|
444
|
+
1. Fork edin
|
|
445
|
+
2. Feature branch oluşturun (`git checkout -b feature/amazing-feature`)
|
|
446
|
+
3. Commit edin (`git commit -m 'Add amazing feature'`)
|
|
447
|
+
4. Push edin (`git push origin feature/amazing-feature`)
|
|
448
|
+
5. Pull Request açın
|
|
449
|
+
|
|
450
|
+
## ⭐ Özellik İstekleri
|
|
451
|
+
|
|
452
|
+
- [ ] Pencere gruplandırma
|
|
453
|
+
- [ ] Hotkey desteği
|
|
454
|
+
- [ ] Pencere filtreleme
|
|
455
|
+
- [ ] Çoklu seçim modu
|
|
456
|
+
- [ ] Screenshot alma
|
|
457
|
+
- [ ] Window history
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
**Not**: Bu modül sadece macOS'ta çalışır ve sistem izinleri gerektirir.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const WindowSelector = require('./window-selector');
|
|
4
|
+
|
|
5
|
+
async function autoBringToFrontDemo() {
|
|
6
|
+
console.log('🤖 Auto Bring-To-Front Demo');
|
|
7
|
+
console.log('============================\n');
|
|
8
|
+
|
|
9
|
+
const selector = new WindowSelector();
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
console.log('🔄 Enabling auto bring-to-front feature...');
|
|
13
|
+
selector.setBringToFrontEnabled(true);
|
|
14
|
+
|
|
15
|
+
console.log('✅ Auto mode enabled!');
|
|
16
|
+
console.log('🖱️ Now move your cursor over different windows');
|
|
17
|
+
console.log('🔝 Each window should automatically come to front\n');
|
|
18
|
+
|
|
19
|
+
let windowCount = 0;
|
|
20
|
+
let lastWindowId = null;
|
|
21
|
+
|
|
22
|
+
selector.on('windowEntered', (window) => {
|
|
23
|
+
if (window.id !== lastWindowId) {
|
|
24
|
+
windowCount++;
|
|
25
|
+
console.log(`[${windowCount}] 🎯 AUTO-FRONT: ${window.appName} - "${window.title}"`);
|
|
26
|
+
console.log(` 📍 Position: (${window.x}, ${window.y})`);
|
|
27
|
+
console.log(` 📏 Size: ${window.width} × ${window.height}`);
|
|
28
|
+
console.log(` 🔝 Window should come to front automatically!\n`);
|
|
29
|
+
lastWindowId = window.id;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
selector.on('windowLeft', (window) => {
|
|
34
|
+
console.log(`🚪 Left: ${window.appName} - "${window.title}"\n`);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
await selector.startSelection();
|
|
38
|
+
|
|
39
|
+
console.log('Demo started! Move cursor over different app windows to see them come to front.');
|
|
40
|
+
console.log('Press Ctrl+C to stop\n');
|
|
41
|
+
|
|
42
|
+
// Auto-stop after 60 seconds
|
|
43
|
+
setTimeout(async () => {
|
|
44
|
+
console.log('\n⏰ Demo completed!');
|
|
45
|
+
console.log(`📊 Total windows auto-focused: ${windowCount}`);
|
|
46
|
+
selector.setBringToFrontEnabled(false);
|
|
47
|
+
await selector.cleanup();
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}, 60000);
|
|
50
|
+
|
|
51
|
+
// Manual stop
|
|
52
|
+
process.on('SIGINT', async () => {
|
|
53
|
+
console.log('\n\n🛑 Stopping demo...');
|
|
54
|
+
console.log(`📊 Total windows auto-focused: ${windowCount}`);
|
|
55
|
+
selector.setBringToFrontEnabled(false);
|
|
56
|
+
await selector.cleanup();
|
|
57
|
+
process.exit(0);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Prevent exit
|
|
61
|
+
setInterval(() => {}, 1000);
|
|
62
|
+
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error('❌ Error:', error.message);
|
|
65
|
+
await selector.cleanup();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (require.main === module) {
|
|
70
|
+
autoBringToFrontDemo();
|
|
71
|
+
}
|
package/binding.gyp
CHANGED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const WindowSelector = require('./window-selector');
|
|
4
|
+
|
|
5
|
+
async function testBringToFront() {
|
|
6
|
+
console.log('🔝 Bring To Front Test');
|
|
7
|
+
console.log('======================\n');
|
|
8
|
+
|
|
9
|
+
const selector = new WindowSelector();
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
// Test 1: Manual bring to front
|
|
13
|
+
console.log('📋 Test 1: Manual window bring-to-front');
|
|
14
|
+
console.log('Move cursor over a window and press SPACE to bring it to front\n');
|
|
15
|
+
|
|
16
|
+
let currentWindow = null;
|
|
17
|
+
|
|
18
|
+
selector.on('windowEntered', (window) => {
|
|
19
|
+
currentWindow = window;
|
|
20
|
+
console.log(`\n🏠 Window: ${window.appName} - "${window.title}" (ID: ${window.id})`);
|
|
21
|
+
console.log(' 📍 Position:', `(${window.x}, ${window.y})`);
|
|
22
|
+
console.log(' 📏 Size:', `${window.width} × ${window.height}`);
|
|
23
|
+
console.log(' 💡 Press SPACE to bring this window to front');
|
|
24
|
+
console.log(' 💡 Press A to enable AUTO bring-to-front');
|
|
25
|
+
console.log(' 💡 Press D to disable AUTO bring-to-front');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
selector.on('windowLeft', (window) => {
|
|
29
|
+
console.log(`🚪 Left: ${window.appName} - "${window.title}"`);
|
|
30
|
+
currentWindow = null;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Keyboard controls
|
|
34
|
+
const readline = require('readline');
|
|
35
|
+
readline.emitKeypressEvents(process.stdin);
|
|
36
|
+
if (process.stdin.isTTY) {
|
|
37
|
+
process.stdin.setRawMode(true);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
process.stdin.on('keypress', async (str, key) => {
|
|
41
|
+
if (key.name === 'space' && currentWindow) {
|
|
42
|
+
console.log(`\n🔝 Bringing window to front: ${currentWindow.appName} - "${currentWindow.title}"`);
|
|
43
|
+
try {
|
|
44
|
+
const success = await selector.bringWindowToFront(currentWindow.id);
|
|
45
|
+
if (success) {
|
|
46
|
+
console.log(' ✅ Window brought to front successfully!');
|
|
47
|
+
} else {
|
|
48
|
+
console.log(' ❌ Failed to bring window to front');
|
|
49
|
+
}
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.log(' ❌ Error:', error.message);
|
|
52
|
+
}
|
|
53
|
+
} else if (key.name === 'a') {
|
|
54
|
+
console.log('\n🔄 Enabling AUTO bring-to-front mode...');
|
|
55
|
+
selector.setBringToFrontEnabled(true);
|
|
56
|
+
console.log(' ✅ Auto mode ON - Windows will come to front automatically');
|
|
57
|
+
} else if (key.name === 'd') {
|
|
58
|
+
console.log('\n🔄 Disabling AUTO bring-to-front mode...');
|
|
59
|
+
selector.setBringToFrontEnabled(false);
|
|
60
|
+
console.log(' ✅ Auto mode OFF - Manual control only');
|
|
61
|
+
} else if (key.ctrl && key.name === 'c') {
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
console.log('🚀 Starting window selection...\n');
|
|
67
|
+
console.log('📋 Controls:');
|
|
68
|
+
console.log(' SPACE - Bring current window to front');
|
|
69
|
+
console.log(' A - Enable AUTO bring-to-front');
|
|
70
|
+
console.log(' D - Disable AUTO bring-to-front');
|
|
71
|
+
console.log(' Ctrl+C - Exit\n');
|
|
72
|
+
|
|
73
|
+
await selector.startSelection();
|
|
74
|
+
|
|
75
|
+
// Keep running
|
|
76
|
+
process.on('SIGINT', async () => {
|
|
77
|
+
console.log('\n🛑 Stopping...');
|
|
78
|
+
await selector.cleanup();
|
|
79
|
+
process.exit(0);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Prevent exit
|
|
83
|
+
setInterval(() => {}, 1000);
|
|
84
|
+
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error('❌ Error:', error.message);
|
|
87
|
+
console.error(error.stack);
|
|
88
|
+
} finally {
|
|
89
|
+
// Cleanup
|
|
90
|
+
await selector.cleanup();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function testAutoBringToFront() {
|
|
95
|
+
console.log('🤖 Auto Bring To Front Test');
|
|
96
|
+
console.log('============================\n');
|
|
97
|
+
|
|
98
|
+
const selector = new WindowSelector();
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
// Enable auto bring-to-front
|
|
102
|
+
console.log('🔄 Enabling auto bring-to-front...');
|
|
103
|
+
selector.setBringToFrontEnabled(true);
|
|
104
|
+
|
|
105
|
+
let windowCount = 0;
|
|
106
|
+
|
|
107
|
+
selector.on('windowEntered', (window) => {
|
|
108
|
+
windowCount++;
|
|
109
|
+
console.log(`\n[${windowCount}] 🔝 AUTO FRONT: ${window.appName} - "${window.title}"`);
|
|
110
|
+
console.log(` 📍 Position: (${window.x}, ${window.y})`);
|
|
111
|
+
console.log(` 📏 Size: ${window.width} × ${window.height}`);
|
|
112
|
+
console.log(' 🚀 Window should automatically come to front!');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
console.log('✅ Auto bring-to-front enabled');
|
|
116
|
+
console.log('🖱️ Move cursor over different windows');
|
|
117
|
+
console.log('🔝 Each window should automatically come to front');
|
|
118
|
+
console.log('⏱️ Test will run for 30 seconds\n');
|
|
119
|
+
|
|
120
|
+
await selector.startSelection();
|
|
121
|
+
|
|
122
|
+
// Auto-stop after 30 seconds
|
|
123
|
+
setTimeout(async () => {
|
|
124
|
+
console.log('\n⏰ Test completed!');
|
|
125
|
+
console.log(`📊 Total windows auto-focused: ${windowCount}`);
|
|
126
|
+
selector.setBringToFrontEnabled(false);
|
|
127
|
+
await selector.cleanup();
|
|
128
|
+
process.exit(0);
|
|
129
|
+
}, 30000);
|
|
130
|
+
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error('❌ Error:', error.message);
|
|
133
|
+
await selector.cleanup();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Main function
|
|
138
|
+
async function main() {
|
|
139
|
+
const args = process.argv.slice(2);
|
|
140
|
+
|
|
141
|
+
if (args.includes('--auto')) {
|
|
142
|
+
await testAutoBringToFront();
|
|
143
|
+
} else if (args.includes('--help')) {
|
|
144
|
+
console.log('Bring To Front Tests:');
|
|
145
|
+
console.log('====================');
|
|
146
|
+
console.log('node bring-to-front-test.js [option]');
|
|
147
|
+
console.log('');
|
|
148
|
+
console.log('Options:');
|
|
149
|
+
console.log(' --manual Manual bring-to-front test (default)');
|
|
150
|
+
console.log(' --auto Auto bring-to-front test');
|
|
151
|
+
console.log(' --help Show this help');
|
|
152
|
+
} else {
|
|
153
|
+
await testBringToFront();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (require.main === module) {
|
|
158
|
+
main().catch(console.error);
|
|
159
|
+
}
|