node-mac-recorder 2.17.19 → 2.17.21
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 +3 -1
- package/index.js +21 -200
- package/package.json +1 -1
- package/publish.sh +18 -0
- package/src/cursor_tracker.mm +37 -20
- package/cursor-data-1751364226346.json +0 -1
- package/cursor-data-1751364314136.json +0 -1
- package/cursor-data.json +0 -1
- package/cursor-debug-test.js +0 -60
- package/cursor-dpr-test.js +0 -73
- package/cursor-dpr-test.json +0 -1
- package/cursor-macbook-test.js +0 -63
- package/cursor-permission-test.js +0 -46
- package/cursor-scaling-debug.js +0 -53
- package/cursor-simple-test.js +0 -26
- package/debug-audio.js +0 -79
- package/debug-coordinates.js +0 -69
- package/debug-cursor-output.json +0 -1
- package/debug-macos14.js +0 -110
- package/debug-primary-window.js +0 -84
- package/debug-screen-selection.js +0 -81
- package/debug-window-selector.js +0 -178
- package/examples/electron-integration-example.js +0 -230
- package/examples/electron-preload.js +0 -46
- package/examples/electron-renderer.html +0 -634
- package/examples/integration-example.js +0 -228
- package/examples/window-selector-example.js +0 -254
- package/quick-cursor-test.json +0 -1
- package/test-both-cursor.json +0 -1
- package/test-cursor-fix.js +0 -105
- package/test-cursor-types.js +0 -117
- package/test-display-coordinates.js +0 -72
- package/test-integrated-recording.js +0 -120
- package/test-menubar-offset.js +0 -110
- package/test-output/primary-fix-test-1758266910543.json +0 -1
- package/test-output/unified-cursor-1758313640878.json +0 -1
- package/test-output/unified-cursor-1758313689471.json +0 -1
- package/test-primary-cursor.js +0 -154
- package/test-primary-fix.js +0 -120
- package/test-unified-cursor.js +0 -75
- package/test-window-recording.js +0 -149
package/debug-window-selector.js
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const WindowSelector = require('./window-selector');
|
|
4
|
-
|
|
5
|
-
async function debugWindowSelector() {
|
|
6
|
-
console.log('🔍 Window Selector Debug Mode');
|
|
7
|
-
console.log('=============================\n');
|
|
8
|
-
|
|
9
|
-
const selector = new WindowSelector();
|
|
10
|
-
|
|
11
|
-
try {
|
|
12
|
-
// 1. İzin kontrolü
|
|
13
|
-
console.log('1️⃣ Checking permissions...');
|
|
14
|
-
const permissions = await selector.checkPermissions();
|
|
15
|
-
console.log('Permissions:', JSON.stringify(permissions, null, 2));
|
|
16
|
-
|
|
17
|
-
if (!permissions.screenRecording || !permissions.accessibility) {
|
|
18
|
-
console.warn('⚠️ Missing permissions detected!');
|
|
19
|
-
console.warn('Go to: System Preferences > Security & Privacy > Privacy');
|
|
20
|
-
console.warn('Enable for Terminal/Node in both:');
|
|
21
|
-
console.warn('- Screen Recording');
|
|
22
|
-
console.warn('- Accessibility');
|
|
23
|
-
console.log();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// 2. Native status before start
|
|
27
|
-
console.log('\n2️⃣ Native status before start:');
|
|
28
|
-
const initialStatus = selector.getStatus();
|
|
29
|
-
console.log(JSON.stringify(initialStatus, null, 2));
|
|
30
|
-
|
|
31
|
-
// 3. Start selection with detailed logging
|
|
32
|
-
console.log('\n3️⃣ Starting window selection...');
|
|
33
|
-
|
|
34
|
-
selector.on('selectionStarted', () => {
|
|
35
|
-
console.log('✅ Selection started event received');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
selector.on('windowEntered', (window) => {
|
|
39
|
-
console.log(`🏠 Window entered: "${window.title}" (${window.appName})`);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
selector.on('windowLeft', (window) => {
|
|
43
|
-
console.log(`🚪 Window left: "${window.title}" (${window.appName})`);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
selector.on('windowSelected', (window) => {
|
|
47
|
-
console.log('🎯 Window selected:', window.title);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
selector.on('error', (error) => {
|
|
51
|
-
console.error('❌ Error event:', error);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
await selector.startSelection();
|
|
55
|
-
|
|
56
|
-
// 4. Status after start
|
|
57
|
-
console.log('\n4️⃣ Status after start:');
|
|
58
|
-
const runningStatus = selector.getStatus();
|
|
59
|
-
console.log(JSON.stringify(runningStatus, null, 2));
|
|
60
|
-
|
|
61
|
-
// 5. Detailed native status monitoring
|
|
62
|
-
console.log('\n5️⃣ Monitoring native status (10 seconds)...');
|
|
63
|
-
console.log('Move your cursor over different windows');
|
|
64
|
-
console.log('The overlay should appear over windows\n');
|
|
65
|
-
|
|
66
|
-
for (let i = 0; i < 20; i++) {
|
|
67
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
68
|
-
const status = selector.getStatus();
|
|
69
|
-
|
|
70
|
-
process.stdout.write(`\r[${i+1}/20] `);
|
|
71
|
-
process.stdout.write(`Selecting: ${status.nativeStatus?.isSelecting || false}, `);
|
|
72
|
-
process.stdout.write(`Overlay: ${status.nativeStatus?.hasOverlay || false}, `);
|
|
73
|
-
process.stdout.write(`Windows: ${status.nativeStatus?.windowCount || 0}`);
|
|
74
|
-
|
|
75
|
-
if (status.nativeStatus?.currentWindow) {
|
|
76
|
-
process.stdout.write(`, Current: ${status.nativeStatus.currentWindow.appName}`);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
console.log('\n\n6️⃣ Final status:');
|
|
81
|
-
const finalStatus = selector.getStatus();
|
|
82
|
-
console.log(JSON.stringify(finalStatus, null, 2));
|
|
83
|
-
|
|
84
|
-
} catch (error) {
|
|
85
|
-
console.error('\n❌ Debug failed:', error.message);
|
|
86
|
-
console.error('Stack:', error.stack);
|
|
87
|
-
} finally {
|
|
88
|
-
console.log('\n🛑 Stopping selection...');
|
|
89
|
-
await selector.cleanup();
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Alternative: Test native functions directly
|
|
94
|
-
async function testNativeFunctions() {
|
|
95
|
-
console.log('🧪 Testing Native Functions Directly');
|
|
96
|
-
console.log('====================================\n');
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
// Try to load native binding directly
|
|
100
|
-
let nativeBinding;
|
|
101
|
-
try {
|
|
102
|
-
nativeBinding = require("./build/Release/mac_recorder.node");
|
|
103
|
-
} catch (error) {
|
|
104
|
-
try {
|
|
105
|
-
nativeBinding = require("./build/Debug/mac_recorder.node");
|
|
106
|
-
} catch (debugError) {
|
|
107
|
-
console.error('❌ Cannot load native module');
|
|
108
|
-
console.error('Release error:', error.message);
|
|
109
|
-
console.error('Debug error:', debugError.message);
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
console.log('✅ Native module loaded successfully');
|
|
115
|
-
|
|
116
|
-
// Test if window selector functions exist
|
|
117
|
-
console.log('\n🔍 Available native functions:');
|
|
118
|
-
const functions = [
|
|
119
|
-
'startWindowSelection',
|
|
120
|
-
'stopWindowSelection',
|
|
121
|
-
'getSelectedWindowInfo',
|
|
122
|
-
'getWindowSelectionStatus'
|
|
123
|
-
];
|
|
124
|
-
|
|
125
|
-
for (const func of functions) {
|
|
126
|
-
if (typeof nativeBinding[func] === 'function') {
|
|
127
|
-
console.log(`✅ ${func} - available`);
|
|
128
|
-
} else {
|
|
129
|
-
console.log(`❌ ${func} - missing`);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Test direct native call
|
|
134
|
-
console.log('\n🚀 Testing direct native startWindowSelection...');
|
|
135
|
-
try {
|
|
136
|
-
const result = nativeBinding.startWindowSelection();
|
|
137
|
-
console.log('Native start result:', result);
|
|
138
|
-
|
|
139
|
-
if (result) {
|
|
140
|
-
console.log('✅ Native selection started');
|
|
141
|
-
|
|
142
|
-
// Check status
|
|
143
|
-
const status = nativeBinding.getWindowSelectionStatus();
|
|
144
|
-
console.log('Native status:', JSON.stringify(status, null, 2));
|
|
145
|
-
|
|
146
|
-
// Wait a bit
|
|
147
|
-
console.log('\nWaiting 3 seconds for overlay to appear...');
|
|
148
|
-
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
149
|
-
|
|
150
|
-
// Stop
|
|
151
|
-
const stopResult = nativeBinding.stopWindowSelection();
|
|
152
|
-
console.log('Native stop result:', stopResult);
|
|
153
|
-
} else {
|
|
154
|
-
console.log('❌ Native selection failed to start');
|
|
155
|
-
}
|
|
156
|
-
} catch (nativeError) {
|
|
157
|
-
console.error('❌ Native function error:', nativeError.message);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
} catch (error) {
|
|
161
|
-
console.error('❌ Native test failed:', error.message);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Main function
|
|
166
|
-
async function main() {
|
|
167
|
-
const args = process.argv.slice(2);
|
|
168
|
-
|
|
169
|
-
if (args.includes('--native')) {
|
|
170
|
-
await testNativeFunctions();
|
|
171
|
-
} else {
|
|
172
|
-
await debugWindowSelector();
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (require.main === module) {
|
|
177
|
-
main().catch(console.error);
|
|
178
|
-
}
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
// Electron Integration Example for node-mac-recorder
|
|
2
|
-
// This example shows how to use the Electron-safe version in an Electron app
|
|
3
|
-
|
|
4
|
-
const { app, BrowserWindow, ipcMain, dialog } = require("electron");
|
|
5
|
-
const path = require("path");
|
|
6
|
-
|
|
7
|
-
// Import the Electron-safe version
|
|
8
|
-
const ElectronSafeMacRecorder = require("../electron-safe-index");
|
|
9
|
-
|
|
10
|
-
let mainWindow;
|
|
11
|
-
let recorder;
|
|
12
|
-
|
|
13
|
-
function createWindow() {
|
|
14
|
-
// Create the browser window
|
|
15
|
-
mainWindow = new BrowserWindow({
|
|
16
|
-
width: 1200,
|
|
17
|
-
height: 800,
|
|
18
|
-
webPreferences: {
|
|
19
|
-
nodeIntegration: false,
|
|
20
|
-
contextIsolation: true,
|
|
21
|
-
preload: path.join(__dirname, "electron-preload.js"),
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// Load the app
|
|
26
|
-
mainWindow.loadFile("electron-renderer.html");
|
|
27
|
-
|
|
28
|
-
// Initialize the Electron-safe recorder
|
|
29
|
-
try {
|
|
30
|
-
recorder = new ElectronSafeMacRecorder();
|
|
31
|
-
console.log("✅ ElectronSafeMacRecorder initialized");
|
|
32
|
-
|
|
33
|
-
// Setup event listeners
|
|
34
|
-
recorder.on("recordingStarted", (data) => {
|
|
35
|
-
console.log("🎬 Recording started:", data);
|
|
36
|
-
mainWindow.webContents.send("recording-started", data);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
recorder.on("stopped", (result) => {
|
|
40
|
-
console.log("🛑 Recording stopped:", result);
|
|
41
|
-
mainWindow.webContents.send("recording-stopped", result);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
recorder.on("completed", (outputPath) => {
|
|
45
|
-
console.log("✅ Recording completed:", outputPath);
|
|
46
|
-
mainWindow.webContents.send("recording-completed", outputPath);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
recorder.on("timeUpdate", (elapsed) => {
|
|
50
|
-
mainWindow.webContents.send("recording-time-update", elapsed);
|
|
51
|
-
});
|
|
52
|
-
} catch (error) {
|
|
53
|
-
console.error("❌ Failed to initialize recorder:", error);
|
|
54
|
-
dialog.showErrorBox(
|
|
55
|
-
"Recorder Error",
|
|
56
|
-
"Failed to initialize screen recorder. Please ensure the Electron-safe module is built."
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// IPC handlers for safe communication with renderer
|
|
62
|
-
ipcMain.handle("recorder:getModuleInfo", async () => {
|
|
63
|
-
try {
|
|
64
|
-
return recorder ? recorder.getModuleInfo() : null;
|
|
65
|
-
} catch (error) {
|
|
66
|
-
console.error("Error getting module info:", error);
|
|
67
|
-
return { error: error.message };
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
ipcMain.handle("recorder:checkPermissions", async () => {
|
|
72
|
-
try {
|
|
73
|
-
return await recorder.checkPermissions();
|
|
74
|
-
} catch (error) {
|
|
75
|
-
console.error("Error checking permissions:", error);
|
|
76
|
-
return { error: error.message };
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
ipcMain.handle("recorder:getDisplays", async () => {
|
|
81
|
-
try {
|
|
82
|
-
return await recorder.getDisplays();
|
|
83
|
-
} catch (error) {
|
|
84
|
-
console.error("Error getting displays:", error);
|
|
85
|
-
return [];
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
ipcMain.handle("recorder:getWindows", async () => {
|
|
90
|
-
try {
|
|
91
|
-
return await recorder.getWindows();
|
|
92
|
-
} catch (error) {
|
|
93
|
-
console.error("Error getting windows:", error);
|
|
94
|
-
return [];
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
ipcMain.handle(
|
|
99
|
-
"recorder:startRecording",
|
|
100
|
-
async (event, outputPath, options) => {
|
|
101
|
-
try {
|
|
102
|
-
if (!recorder) {
|
|
103
|
-
throw new Error("Recorder not initialized");
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
console.log("🎬 Starting recording with options:", options);
|
|
107
|
-
const result = await recorder.startRecording(outputPath, options);
|
|
108
|
-
return { success: true, result };
|
|
109
|
-
} catch (error) {
|
|
110
|
-
console.error("Error starting recording:", error);
|
|
111
|
-
return { success: false, error: error.message };
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
ipcMain.handle("recorder:stopRecording", async () => {
|
|
117
|
-
try {
|
|
118
|
-
if (!recorder) {
|
|
119
|
-
throw new Error("Recorder not initialized");
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
console.log("🛑 Stopping recording");
|
|
123
|
-
const result = await recorder.stopRecording();
|
|
124
|
-
return { success: true, result };
|
|
125
|
-
} catch (error) {
|
|
126
|
-
console.error("Error stopping recording:", error);
|
|
127
|
-
return { success: false, error: error.message };
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
ipcMain.handle("recorder:getStatus", async () => {
|
|
132
|
-
try {
|
|
133
|
-
return recorder ? recorder.getStatus() : null;
|
|
134
|
-
} catch (error) {
|
|
135
|
-
console.error("Error getting status:", error);
|
|
136
|
-
return { error: error.message };
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
ipcMain.handle("recorder:getCursorPosition", async () => {
|
|
141
|
-
try {
|
|
142
|
-
return recorder ? recorder.getCursorPosition() : null;
|
|
143
|
-
} catch (error) {
|
|
144
|
-
console.error("Error getting cursor position:", error);
|
|
145
|
-
return { error: error.message };
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
ipcMain.handle(
|
|
150
|
-
"recorder:getDisplayThumbnail",
|
|
151
|
-
async (event, displayId, options) => {
|
|
152
|
-
try {
|
|
153
|
-
return await recorder.getDisplayThumbnail(displayId, options);
|
|
154
|
-
} catch (error) {
|
|
155
|
-
console.error("Error getting display thumbnail:", error);
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
ipcMain.handle(
|
|
162
|
-
"recorder:getWindowThumbnail",
|
|
163
|
-
async (event, windowId, options) => {
|
|
164
|
-
try {
|
|
165
|
-
return await recorder.getWindowThumbnail(windowId, options);
|
|
166
|
-
} catch (error) {
|
|
167
|
-
console.error("Error getting window thumbnail:", error);
|
|
168
|
-
return null;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
ipcMain.handle("dialog:showSaveDialog", async () => {
|
|
174
|
-
const result = await dialog.showSaveDialog(mainWindow, {
|
|
175
|
-
title: "Save Recording",
|
|
176
|
-
defaultPath: "recording.mov",
|
|
177
|
-
filters: [{ name: "Movies", extensions: ["mov", "mp4"] }],
|
|
178
|
-
});
|
|
179
|
-
return result;
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
// App event listeners
|
|
183
|
-
app.whenReady().then(createWindow);
|
|
184
|
-
|
|
185
|
-
app.on("window-all-closed", () => {
|
|
186
|
-
// Stop any ongoing recording before quitting
|
|
187
|
-
if (recorder && recorder.getStatus().isRecording) {
|
|
188
|
-
console.log("🛑 Stopping recording before quit");
|
|
189
|
-
recorder.stopRecording().finally(() => {
|
|
190
|
-
if (process.platform !== "darwin") {
|
|
191
|
-
app.quit();
|
|
192
|
-
}
|
|
193
|
-
});
|
|
194
|
-
} else {
|
|
195
|
-
if (process.platform !== "darwin") {
|
|
196
|
-
app.quit();
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
app.on("activate", () => {
|
|
202
|
-
if (BrowserWindow.getAllWindows().length === 0) {
|
|
203
|
-
createWindow();
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// Handle app termination gracefully
|
|
208
|
-
process.on("SIGINT", async () => {
|
|
209
|
-
console.log("🛑 SIGINT received, stopping recording...");
|
|
210
|
-
if (recorder && recorder.getStatus().isRecording) {
|
|
211
|
-
try {
|
|
212
|
-
await recorder.stopRecording();
|
|
213
|
-
} catch (error) {
|
|
214
|
-
console.error("Error stopping recording on exit:", error);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
app.quit();
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
process.on("SIGTERM", async () => {
|
|
221
|
-
console.log("🛑 SIGTERM received, stopping recording...");
|
|
222
|
-
if (recorder && recorder.getStatus().isRecording) {
|
|
223
|
-
try {
|
|
224
|
-
await recorder.stopRecording();
|
|
225
|
-
} catch (error) {
|
|
226
|
-
console.error("Error stopping recording on exit:", error);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
app.quit();
|
|
230
|
-
});
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
// Preload script for secure IPC communication
|
|
2
|
-
const { contextBridge, ipcRenderer } = require("electron");
|
|
3
|
-
|
|
4
|
-
// Expose protected methods that allow the renderer process to use
|
|
5
|
-
// the ipcRenderer without exposing the entire object
|
|
6
|
-
contextBridge.exposeInMainWorld("electronAPI", {
|
|
7
|
-
// Recorder API
|
|
8
|
-
recorder: {
|
|
9
|
-
getModuleInfo: () => ipcRenderer.invoke("recorder:getModuleInfo"),
|
|
10
|
-
checkPermissions: () => ipcRenderer.invoke("recorder:checkPermissions"),
|
|
11
|
-
getDisplays: () => ipcRenderer.invoke("recorder:getDisplays"),
|
|
12
|
-
getWindows: () => ipcRenderer.invoke("recorder:getWindows"),
|
|
13
|
-
startRecording: (outputPath, options) =>
|
|
14
|
-
ipcRenderer.invoke("recorder:startRecording", outputPath, options),
|
|
15
|
-
stopRecording: () => ipcRenderer.invoke("recorder:stopRecording"),
|
|
16
|
-
getStatus: () => ipcRenderer.invoke("recorder:getStatus"),
|
|
17
|
-
getCursorPosition: () => ipcRenderer.invoke("recorder:getCursorPosition"),
|
|
18
|
-
getDisplayThumbnail: (displayId, options) =>
|
|
19
|
-
ipcRenderer.invoke("recorder:getDisplayThumbnail", displayId, options),
|
|
20
|
-
getWindowThumbnail: (windowId, options) =>
|
|
21
|
-
ipcRenderer.invoke("recorder:getWindowThumbnail", windowId, options),
|
|
22
|
-
|
|
23
|
-
// Event listeners
|
|
24
|
-
onRecordingStarted: (callback) =>
|
|
25
|
-
ipcRenderer.on("recording-started", callback),
|
|
26
|
-
onRecordingStopped: (callback) =>
|
|
27
|
-
ipcRenderer.on("recording-stopped", callback),
|
|
28
|
-
onRecordingCompleted: (callback) =>
|
|
29
|
-
ipcRenderer.on("recording-completed", callback),
|
|
30
|
-
onTimeUpdate: (callback) =>
|
|
31
|
-
ipcRenderer.on("recording-time-update", callback),
|
|
32
|
-
|
|
33
|
-
// Remove listeners
|
|
34
|
-
removeAllListeners: () => {
|
|
35
|
-
ipcRenderer.removeAllListeners("recording-started");
|
|
36
|
-
ipcRenderer.removeAllListeners("recording-stopped");
|
|
37
|
-
ipcRenderer.removeAllListeners("recording-completed");
|
|
38
|
-
ipcRenderer.removeAllListeners("recording-time-update");
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
// Dialog API
|
|
43
|
-
dialog: {
|
|
44
|
-
showSaveDialog: () => ipcRenderer.invoke("dialog:showSaveDialog"),
|
|
45
|
-
},
|
|
46
|
-
});
|