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,160 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const WindowSelector = require('./window-selector');
|
|
4
|
+
const readline = require('readline');
|
|
5
|
+
|
|
6
|
+
async function main() {
|
|
7
|
+
console.log('🔍 Window Selector Test');
|
|
8
|
+
console.log('=======================\n');
|
|
9
|
+
|
|
10
|
+
const selector = new WindowSelector();
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
// Permissions kontrolü
|
|
14
|
+
console.log('1️⃣ Checking permissions...');
|
|
15
|
+
const permissions = await selector.checkPermissions();
|
|
16
|
+
console.log('Permissions:', permissions);
|
|
17
|
+
|
|
18
|
+
if (!permissions.screenRecording || !permissions.accessibility) {
|
|
19
|
+
console.warn('⚠️ Warning: Some permissions missing. Go to System Preferences > Security & Privacy');
|
|
20
|
+
console.warn(' - Privacy > Screen Recording: Enable for Terminal/Node');
|
|
21
|
+
console.warn(' - Privacy > Accessibility: Enable for Terminal/Node');
|
|
22
|
+
console.log();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Event listener'ları ayarla
|
|
26
|
+
selector.on('selectionStarted', () => {
|
|
27
|
+
console.log('✅ Window selection started');
|
|
28
|
+
console.log('🖱️ Move your cursor over windows to highlight them');
|
|
29
|
+
console.log('🎯 Click "Select Window" button to choose a window');
|
|
30
|
+
console.log('❌ Press Ctrl+C to cancel\n');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
selector.on('windowEntered', (window) => {
|
|
34
|
+
console.log(`🏠 Entered window: "${window.title}" - ${window.appName}`);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
selector.on('windowLeft', (window) => {
|
|
38
|
+
console.log(`🚪 Left window: "${window.title}" - ${window.appName}`);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
selector.on('windowSelected', (windowInfo) => {
|
|
42
|
+
console.log('\n🎉 Window Selected!');
|
|
43
|
+
console.log('==================');
|
|
44
|
+
console.log(`Title: "${windowInfo.title}"`);
|
|
45
|
+
console.log(`Application: ${windowInfo.appName}`);
|
|
46
|
+
console.log(`Position: (${windowInfo.x}, ${windowInfo.y})`);
|
|
47
|
+
console.log(`Size: ${windowInfo.width} x ${windowInfo.height}`);
|
|
48
|
+
console.log(`Screen ID: ${windowInfo.screenId}`);
|
|
49
|
+
console.log(`Screen Position: (${windowInfo.screenX}, ${windowInfo.screenY})`);
|
|
50
|
+
console.log(`Screen Size: ${windowInfo.screenWidth} x ${windowInfo.screenHeight}`);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
selector.on('selectionStopped', () => {
|
|
54
|
+
console.log('🛑 Window selection stopped');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
selector.on('error', (error) => {
|
|
58
|
+
console.error('❌ Error:', error.message);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Ctrl+C handler
|
|
62
|
+
process.on('SIGINT', async () => {
|
|
63
|
+
console.log('\n\n🛑 Stopping window selection...');
|
|
64
|
+
await selector.cleanup();
|
|
65
|
+
process.exit(0);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
console.log('2️⃣ Testing window selection...\n');
|
|
69
|
+
|
|
70
|
+
// Seçim başlat
|
|
71
|
+
const selectedWindow = await selector.selectWindow();
|
|
72
|
+
|
|
73
|
+
if (selectedWindow) {
|
|
74
|
+
console.log('\n✨ Final result:');
|
|
75
|
+
console.log(JSON.stringify(selectedWindow, null, 2));
|
|
76
|
+
|
|
77
|
+
// Ek bilgiler
|
|
78
|
+
console.log('\n📊 Additional Analysis:');
|
|
79
|
+
console.log(`Window area: ${selectedWindow.width * selectedWindow.height} pixels`);
|
|
80
|
+
console.log(`Aspect ratio: ${(selectedWindow.width / selectedWindow.height).toFixed(2)}`);
|
|
81
|
+
|
|
82
|
+
// Window bounds relative to screen
|
|
83
|
+
const relativeX = selectedWindow.x - selectedWindow.screenX;
|
|
84
|
+
const relativeY = selectedWindow.y - selectedWindow.screenY;
|
|
85
|
+
console.log(`Relative position on screen: (${relativeX}, ${relativeY})`);
|
|
86
|
+
|
|
87
|
+
if (relativeX < 0 || relativeY < 0 ||
|
|
88
|
+
relativeX + selectedWindow.width > selectedWindow.screenWidth ||
|
|
89
|
+
relativeY + selectedWindow.height > selectedWindow.screenHeight) {
|
|
90
|
+
console.log('⚠️ Window extends beyond screen boundaries (multi-monitor setup)');
|
|
91
|
+
} else {
|
|
92
|
+
console.log('✅ Window is fully contained within its screen');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error('❌ Test failed:', error.message);
|
|
98
|
+
console.error(error.stack);
|
|
99
|
+
} finally {
|
|
100
|
+
await selector.cleanup();
|
|
101
|
+
console.log('\n🧹 Cleanup completed');
|
|
102
|
+
process.exit(0);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Alternative test function for programmatic testing
|
|
107
|
+
async function testWindowSelectorAPI() {
|
|
108
|
+
console.log('🧪 API Test Mode');
|
|
109
|
+
console.log('===============\n');
|
|
110
|
+
|
|
111
|
+
const selector = new WindowSelector();
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
// Test 1: Status before selection
|
|
115
|
+
console.log('Test 1: Initial status');
|
|
116
|
+
const initialStatus = selector.getStatus();
|
|
117
|
+
console.log('Initial status:', initialStatus);
|
|
118
|
+
console.assert(!initialStatus.isSelecting, 'Should not be selecting initially');
|
|
119
|
+
console.assert(!initialStatus.hasSelectedWindow, 'Should not have selected window initially');
|
|
120
|
+
console.log('✅ Initial status test passed\n');
|
|
121
|
+
|
|
122
|
+
// Test 2: Start selection
|
|
123
|
+
console.log('Test 2: Start selection');
|
|
124
|
+
await selector.startSelection();
|
|
125
|
+
const selectingStatus = selector.getStatus();
|
|
126
|
+
console.log('Selecting status:', selectingStatus);
|
|
127
|
+
console.assert(selectingStatus.isSelecting, 'Should be selecting after start');
|
|
128
|
+
console.log('✅ Start selection test passed\n');
|
|
129
|
+
|
|
130
|
+
// Wait a bit to let user move cursor
|
|
131
|
+
console.log('Move your cursor over different windows for 3 seconds...');
|
|
132
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
133
|
+
|
|
134
|
+
// Test 3: Stop selection
|
|
135
|
+
console.log('Test 3: Stop selection');
|
|
136
|
+
await selector.stopSelection();
|
|
137
|
+
const stoppedStatus = selector.getStatus();
|
|
138
|
+
console.log('Stopped status:', stoppedStatus);
|
|
139
|
+
console.assert(!stoppedStatus.isSelecting, 'Should not be selecting after stop');
|
|
140
|
+
console.log('✅ Stop selection test passed\n');
|
|
141
|
+
|
|
142
|
+
console.log('🎉 All API tests passed!');
|
|
143
|
+
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error('❌ API test failed:', error.message);
|
|
146
|
+
throw error;
|
|
147
|
+
} finally {
|
|
148
|
+
await selector.cleanup();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Parse command line arguments
|
|
153
|
+
const args = process.argv.slice(2);
|
|
154
|
+
const testMode = args.includes('--api-test') ? 'api' : 'interactive';
|
|
155
|
+
|
|
156
|
+
if (testMode === 'api') {
|
|
157
|
+
testWindowSelectorAPI().catch(console.error);
|
|
158
|
+
} else {
|
|
159
|
+
main().catch(console.error);
|
|
160
|
+
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
const { EventEmitter } = require("events");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
// Native modülü yükle
|
|
5
|
+
let nativeBinding;
|
|
6
|
+
try {
|
|
7
|
+
nativeBinding = require("./build/Release/mac_recorder.node");
|
|
8
|
+
} catch (error) {
|
|
9
|
+
try {
|
|
10
|
+
nativeBinding = require("./build/Debug/mac_recorder.node");
|
|
11
|
+
} catch (debugError) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
'Native module not found. Please run "npm run build" to compile the native module.\n' +
|
|
14
|
+
"Original error: " +
|
|
15
|
+
error.message
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class WindowSelector extends EventEmitter {
|
|
21
|
+
constructor() {
|
|
22
|
+
super();
|
|
23
|
+
this.isSelecting = false;
|
|
24
|
+
this.selectionTimer = null;
|
|
25
|
+
this.selectedWindow = null;
|
|
26
|
+
this.lastStatus = null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Pencere seçim modunu başlatır
|
|
31
|
+
* İmleç hangi pencerenin üstüne gelirse o pencereyi highlight eder
|
|
32
|
+
* Select butonuna basılınca seçim tamamlanır
|
|
33
|
+
*/
|
|
34
|
+
async startSelection() {
|
|
35
|
+
if (this.isSelecting) {
|
|
36
|
+
throw new Error("Window selection is already in progress");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
try {
|
|
41
|
+
// Native window selection başlat
|
|
42
|
+
const success = nativeBinding.startWindowSelection();
|
|
43
|
+
|
|
44
|
+
if (success) {
|
|
45
|
+
this.isSelecting = true;
|
|
46
|
+
this.selectedWindow = null;
|
|
47
|
+
|
|
48
|
+
// Status polling timer başlat (higher frequency for overlay updates)
|
|
49
|
+
this.selectionTimer = setInterval(() => {
|
|
50
|
+
this.checkSelectionStatus();
|
|
51
|
+
}, 50); // 20 FPS status check for smooth overlay
|
|
52
|
+
|
|
53
|
+
this.emit("selectionStarted");
|
|
54
|
+
resolve(true);
|
|
55
|
+
} else {
|
|
56
|
+
reject(new Error("Failed to start window selection"));
|
|
57
|
+
}
|
|
58
|
+
} catch (error) {
|
|
59
|
+
reject(error);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Pencere seçim modunu durdurur
|
|
66
|
+
*/
|
|
67
|
+
async stopSelection() {
|
|
68
|
+
if (!this.isSelecting) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
try {
|
|
74
|
+
const success = nativeBinding.stopWindowSelection();
|
|
75
|
+
|
|
76
|
+
// Timer'ı durdur
|
|
77
|
+
if (this.selectionTimer) {
|
|
78
|
+
clearInterval(this.selectionTimer);
|
|
79
|
+
this.selectionTimer = null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.isSelecting = false;
|
|
83
|
+
this.lastStatus = null;
|
|
84
|
+
|
|
85
|
+
this.emit("selectionStopped");
|
|
86
|
+
resolve(success);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
reject(error);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Selection durumunu kontrol eder ve event yayar
|
|
95
|
+
*/
|
|
96
|
+
checkSelectionStatus() {
|
|
97
|
+
if (!this.isSelecting) return;
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const status = nativeBinding.getWindowSelectionStatus();
|
|
101
|
+
|
|
102
|
+
// Seçim tamamlandı mı kontrol et
|
|
103
|
+
if (status.hasSelectedWindow && !this.selectedWindow) {
|
|
104
|
+
const windowInfo = nativeBinding.getSelectedWindowInfo();
|
|
105
|
+
if (windowInfo) {
|
|
106
|
+
this.selectedWindow = windowInfo;
|
|
107
|
+
this.isSelecting = false;
|
|
108
|
+
|
|
109
|
+
// Timer'ı durdur
|
|
110
|
+
if (this.selectionTimer) {
|
|
111
|
+
clearInterval(this.selectionTimer);
|
|
112
|
+
this.selectionTimer = null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
this.emit("windowSelected", windowInfo);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Mevcut pencere değişti mi kontrol et
|
|
121
|
+
if (this.lastStatus) {
|
|
122
|
+
const lastWindow = this.lastStatus.currentWindow;
|
|
123
|
+
const currentWindow = status.currentWindow;
|
|
124
|
+
|
|
125
|
+
if (!lastWindow && currentWindow) {
|
|
126
|
+
// Yeni pencere üstüne gelindi
|
|
127
|
+
this.emit("windowEntered", currentWindow);
|
|
128
|
+
} else if (lastWindow && !currentWindow) {
|
|
129
|
+
// Pencere üstünden ayrıldı
|
|
130
|
+
this.emit("windowLeft", lastWindow);
|
|
131
|
+
} else if (lastWindow && currentWindow &&
|
|
132
|
+
(lastWindow.id !== currentWindow.id ||
|
|
133
|
+
lastWindow.title !== currentWindow.title ||
|
|
134
|
+
lastWindow.appName !== currentWindow.appName)) {
|
|
135
|
+
// Farklı bir pencereye geçildi
|
|
136
|
+
this.emit("windowLeft", lastWindow);
|
|
137
|
+
this.emit("windowEntered", currentWindow);
|
|
138
|
+
}
|
|
139
|
+
} else if (!this.lastStatus && status.currentWindow) {
|
|
140
|
+
// İlk pencere detection
|
|
141
|
+
this.emit("windowEntered", status.currentWindow);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
this.lastStatus = status;
|
|
145
|
+
} catch (error) {
|
|
146
|
+
this.emit("error", error);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Seçilen pencere bilgisini döndürür
|
|
152
|
+
*/
|
|
153
|
+
getSelectedWindow() {
|
|
154
|
+
return this.selectedWindow;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Seçim durumunu döndürür
|
|
159
|
+
*/
|
|
160
|
+
getStatus() {
|
|
161
|
+
try {
|
|
162
|
+
const nativeStatus = nativeBinding.getWindowSelectionStatus();
|
|
163
|
+
return {
|
|
164
|
+
isSelecting: this.isSelecting && nativeStatus.isSelecting,
|
|
165
|
+
hasSelectedWindow: !!this.selectedWindow,
|
|
166
|
+
selectedWindow: this.selectedWindow,
|
|
167
|
+
nativeStatus: nativeStatus
|
|
168
|
+
};
|
|
169
|
+
} catch (error) {
|
|
170
|
+
return {
|
|
171
|
+
isSelecting: this.isSelecting,
|
|
172
|
+
hasSelectedWindow: !!this.selectedWindow,
|
|
173
|
+
selectedWindow: this.selectedWindow,
|
|
174
|
+
error: error.message
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Promise tabanlı pencere seçimi
|
|
181
|
+
* Kullanıcı bir pencere seçene kadar bekler
|
|
182
|
+
*/
|
|
183
|
+
async selectWindow() {
|
|
184
|
+
if (this.isSelecting) {
|
|
185
|
+
throw new Error("Selection already in progress");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return new Promise(async (resolve, reject) => {
|
|
189
|
+
try {
|
|
190
|
+
// Event listener'ları ayarla
|
|
191
|
+
const onWindowSelected = (windowInfo) => {
|
|
192
|
+
this.removeAllListeners("windowSelected");
|
|
193
|
+
this.removeAllListeners("error");
|
|
194
|
+
resolve(windowInfo);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const onError = (error) => {
|
|
198
|
+
this.removeAllListeners("windowSelected");
|
|
199
|
+
this.removeAllListeners("error");
|
|
200
|
+
reject(error);
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
this.once("windowSelected", onWindowSelected);
|
|
204
|
+
this.once("error", onError);
|
|
205
|
+
|
|
206
|
+
// Seçimi başlat
|
|
207
|
+
await this.startSelection();
|
|
208
|
+
|
|
209
|
+
} catch (error) {
|
|
210
|
+
this.removeAllListeners("windowSelected");
|
|
211
|
+
this.removeAllListeners("error");
|
|
212
|
+
reject(error);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Pencereyi en öne getirir (focus yapar)
|
|
219
|
+
* @param {number} windowId - Window ID
|
|
220
|
+
* @returns {Promise<boolean>} Success/failure
|
|
221
|
+
*/
|
|
222
|
+
async bringWindowToFront(windowId) {
|
|
223
|
+
if (!windowId) {
|
|
224
|
+
throw new Error("Window ID is required");
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
const success = nativeBinding.bringWindowToFront(windowId);
|
|
229
|
+
return success;
|
|
230
|
+
} catch (error) {
|
|
231
|
+
throw new Error(`Failed to bring window to front: ${error.message}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Otomatik pencere en öne getirme özelliğini aktif/pasif yapar
|
|
237
|
+
* Cursor hangi pencereye gelirse otomatik olarak en öne getirir
|
|
238
|
+
* @param {boolean} enabled - Enable/disable auto bring to front
|
|
239
|
+
*/
|
|
240
|
+
setBringToFrontEnabled(enabled) {
|
|
241
|
+
try {
|
|
242
|
+
nativeBinding.setBringToFrontEnabled(enabled);
|
|
243
|
+
console.log(`🔄 Auto bring-to-front: ${enabled ? 'ENABLED' : 'DISABLED'}`);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
throw new Error(`Failed to set bring to front: ${error.message}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Cleanup - tüm kaynakları temizle
|
|
251
|
+
*/
|
|
252
|
+
async cleanup() {
|
|
253
|
+
if (this.isSelecting) {
|
|
254
|
+
await this.stopSelection();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Timer'ı temizle
|
|
258
|
+
if (this.selectionTimer) {
|
|
259
|
+
clearInterval(this.selectionTimer);
|
|
260
|
+
this.selectionTimer = null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Event listener'ları temizle
|
|
264
|
+
this.removeAllListeners();
|
|
265
|
+
|
|
266
|
+
// State'i sıfırla
|
|
267
|
+
this.selectedWindow = null;
|
|
268
|
+
this.lastStatus = null;
|
|
269
|
+
this.isSelecting = false;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* macOS'ta pencere seçim izinlerini kontrol eder
|
|
274
|
+
*/
|
|
275
|
+
async checkPermissions() {
|
|
276
|
+
try {
|
|
277
|
+
// Mevcut MacRecorder'dan permission check'i kullan
|
|
278
|
+
const MacRecorder = require("./index.js");
|
|
279
|
+
const recorder = new MacRecorder();
|
|
280
|
+
return await recorder.checkPermissions();
|
|
281
|
+
} catch (error) {
|
|
282
|
+
return {
|
|
283
|
+
screenRecording: false,
|
|
284
|
+
accessibility: false,
|
|
285
|
+
error: error.message
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
module.exports = WindowSelector;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const WindowSelector = require('./window-selector');
|
|
4
|
+
|
|
5
|
+
async function workingExample() {
|
|
6
|
+
console.log('🎯 Window Selector - Working Example');
|
|
7
|
+
console.log('====================================\n');
|
|
8
|
+
|
|
9
|
+
const selector = new WindowSelector();
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
console.log('Starting window selection...');
|
|
13
|
+
console.log('Move cursor over different windows to see detection');
|
|
14
|
+
console.log('The system will detect which window is under cursor');
|
|
15
|
+
console.log('Press Ctrl+C to stop\n');
|
|
16
|
+
|
|
17
|
+
let currentWindow = null;
|
|
18
|
+
|
|
19
|
+
selector.on('windowEntered', (window) => {
|
|
20
|
+
currentWindow = window;
|
|
21
|
+
console.log(`\n🏠 ENTERED WINDOW:`);
|
|
22
|
+
console.log(` App: ${window.appName}`);
|
|
23
|
+
console.log(` Title: "${window.title}"`);
|
|
24
|
+
console.log(` Position: (${window.x}, ${window.y})`);
|
|
25
|
+
console.log(` Size: ${window.width} x ${window.height}`);
|
|
26
|
+
console.log(` 💡 This window is now highlighted (overlay may not be visible due to macOS security)`);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
selector.on('windowLeft', (window) => {
|
|
30
|
+
console.log(`\n🚪 LEFT WINDOW: ${window.appName} - "${window.title}"`);
|
|
31
|
+
currentWindow = null;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
selector.on('windowSelected', (selectedWindow) => {
|
|
35
|
+
console.log('\n🎉 WINDOW SELECTED!');
|
|
36
|
+
console.log('==================');
|
|
37
|
+
console.log(`App: ${selectedWindow.appName}`);
|
|
38
|
+
console.log(`Title: "${selectedWindow.title}"`);
|
|
39
|
+
console.log(`Position: (${selectedWindow.x}, ${selectedWindow.y})`);
|
|
40
|
+
console.log(`Size: ${selectedWindow.width} x ${selectedWindow.height}`);
|
|
41
|
+
console.log(`Screen: ${selectedWindow.screenId}`);
|
|
42
|
+
process.exit(0);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Manual selection trigger
|
|
46
|
+
let readline = require('readline');
|
|
47
|
+
const rl = readline.createInterface({
|
|
48
|
+
input: process.stdin,
|
|
49
|
+
output: process.stdout
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
console.log('💡 Pro tip: Press ENTER to select the current window under cursor');
|
|
53
|
+
rl.on('line', () => {
|
|
54
|
+
if (currentWindow) {
|
|
55
|
+
console.log('\n✅ Manually selecting current window...');
|
|
56
|
+
selector.emit('windowSelected', currentWindow);
|
|
57
|
+
} else {
|
|
58
|
+
console.log('\n⚠️ No window under cursor. Move cursor over a window first.');
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
await selector.startSelection();
|
|
63
|
+
|
|
64
|
+
// Status monitoring
|
|
65
|
+
let statusCount = 0;
|
|
66
|
+
const statusInterval = setInterval(() => {
|
|
67
|
+
const status = selector.getStatus();
|
|
68
|
+
statusCount++;
|
|
69
|
+
|
|
70
|
+
if (statusCount % 20 === 0) { // Every 10 seconds
|
|
71
|
+
console.log(`\n📊 Status (${statusCount/2}s): Windows detected: ${status.nativeStatus?.windowCount || 0}`);
|
|
72
|
+
if (status.nativeStatus?.currentWindow) {
|
|
73
|
+
console.log(` Current: ${status.nativeStatus.currentWindow.appName}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}, 500);
|
|
77
|
+
|
|
78
|
+
process.on('SIGINT', async () => {
|
|
79
|
+
clearInterval(statusInterval);
|
|
80
|
+
rl.close();
|
|
81
|
+
console.log('\n🛑 Stopping window selector...');
|
|
82
|
+
await selector.cleanup();
|
|
83
|
+
console.log('✅ Cleanup completed');
|
|
84
|
+
process.exit(0);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error('\n❌ Error:', error.message);
|
|
89
|
+
console.error(error.stack);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
workingExample();
|