node-mac-recorder 1.2.10 → 1.3.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.
@@ -0,0 +1,259 @@
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
+ * Cleanup - tüm kaynakları temizle
219
+ */
220
+ async cleanup() {
221
+ if (this.isSelecting) {
222
+ await this.stopSelection();
223
+ }
224
+
225
+ // Timer'ı temizle
226
+ if (this.selectionTimer) {
227
+ clearInterval(this.selectionTimer);
228
+ this.selectionTimer = null;
229
+ }
230
+
231
+ // Event listener'ları temizle
232
+ this.removeAllListeners();
233
+
234
+ // State'i sıfırla
235
+ this.selectedWindow = null;
236
+ this.lastStatus = null;
237
+ this.isSelecting = false;
238
+ }
239
+
240
+ /**
241
+ * macOS'ta pencere seçim izinlerini kontrol eder
242
+ */
243
+ async checkPermissions() {
244
+ try {
245
+ // Mevcut MacRecorder'dan permission check'i kullan
246
+ const MacRecorder = require("./index.js");
247
+ const recorder = new MacRecorder();
248
+ return await recorder.checkPermissions();
249
+ } catch (error) {
250
+ return {
251
+ screenRecording: false,
252
+ accessibility: false,
253
+ error: error.message
254
+ };
255
+ }
256
+ }
257
+ }
258
+
259
+ 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();