node-mac-recorder 2.17.15 โ 2.17.16
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/index.js +20 -3
- package/package.json +1 -1
- package/src/screen_capture_kit.mm +34 -1
- package/test-cursor-fix.js +105 -0
- package/test-output/cursor-test-window-1758264693010.json +1 -0
package/index.js
CHANGED
|
@@ -830,9 +830,26 @@ class MacRecorder extends EventEmitter {
|
|
|
830
830
|
|
|
831
831
|
if (this.cursorDisplayInfo) {
|
|
832
832
|
if (this.cursorDisplayInfo.windowRelative) {
|
|
833
|
-
// Window recording: Transform
|
|
834
|
-
|
|
835
|
-
|
|
833
|
+
// Window recording: Transform cursor coordinates relative to window's display first
|
|
834
|
+
let adjustedX = position.x;
|
|
835
|
+
let adjustedY = position.y;
|
|
836
|
+
|
|
837
|
+
// If we have target display info, first convert global coords to display-relative
|
|
838
|
+
if (this.cursorDisplayInfo.targetDisplay) {
|
|
839
|
+
adjustedX = position.x - this.cursorDisplayInfo.targetDisplay.x;
|
|
840
|
+
adjustedY = position.y - this.cursorDisplayInfo.targetDisplay.y;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// Then convert display-relative coords to window-relative
|
|
844
|
+
if (this.cursorDisplayInfo.windowInfo && this.cursorDisplayInfo.windowInfo.displayOffsetX !== undefined) {
|
|
845
|
+
x = adjustedX - this.cursorDisplayInfo.windowInfo.displayOffsetX;
|
|
846
|
+
y = adjustedY - this.cursorDisplayInfo.windowInfo.displayOffsetY;
|
|
847
|
+
} else {
|
|
848
|
+
// Fallback: direct window offset from global coordinates
|
|
849
|
+
x = position.x - this.cursorDisplayInfo.x;
|
|
850
|
+
y = position.y - this.cursorDisplayInfo.y;
|
|
851
|
+
}
|
|
852
|
+
|
|
836
853
|
coordinateSystem = "window-relative";
|
|
837
854
|
|
|
838
855
|
// Window bounds check - skip if cursor is outside window
|
package/package.json
CHANGED
|
@@ -119,8 +119,41 @@ static NSString *g_outputPath = nil;
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
if (targetWindow && targetApp) {
|
|
122
|
-
NSLog(@"๐ช Recording window: %@ (%ux%u)",
|
|
122
|
+
NSLog(@"๐ช Recording window: %@ (%ux%u)",
|
|
123
123
|
targetWindow.title, (unsigned)targetWindow.frame.size.width, (unsigned)targetWindow.frame.size.height);
|
|
124
|
+
|
|
125
|
+
// Find which display contains this window for proper cursor coordinate transformation
|
|
126
|
+
CGRect windowFrame = targetWindow.frame;
|
|
127
|
+
NSLog(@"๐ Window frame: (%.0f,%.0f,%.0fx%.0f)",
|
|
128
|
+
windowFrame.origin.x, windowFrame.origin.y,
|
|
129
|
+
windowFrame.size.width, windowFrame.size.height);
|
|
130
|
+
|
|
131
|
+
// Find the display that contains the window's center point
|
|
132
|
+
CGPoint windowCenter = CGPointMake(
|
|
133
|
+
windowFrame.origin.x + windowFrame.size.width / 2,
|
|
134
|
+
windowFrame.origin.y + windowFrame.size.height / 2
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
for (SCDisplay *display in content.displays) {
|
|
138
|
+
CGRect displayFrame = display.frame;
|
|
139
|
+
NSLog(@"๐ Checking if window center (%.0f,%.0f) is in display ID=%u frame (%.0f,%.0f,%.0fx%.0f)",
|
|
140
|
+
windowCenter.x, windowCenter.y, display.displayID,
|
|
141
|
+
displayFrame.origin.x, displayFrame.origin.y,
|
|
142
|
+
displayFrame.size.width, displayFrame.size.height);
|
|
143
|
+
|
|
144
|
+
if (CGRectContainsPoint(displayFrame, windowCenter)) {
|
|
145
|
+
targetDisplay = display;
|
|
146
|
+
NSLog(@"โ
Window is on display ID=%u", display.displayID);
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!targetDisplay) {
|
|
152
|
+
// Fallback: use main display if no display contains the window center
|
|
153
|
+
targetDisplay = content.displays.firstObject;
|
|
154
|
+
NSLog(@"โ ๏ธ Window not contained in any display, using main display ID=%u as fallback", targetDisplay.displayID);
|
|
155
|
+
}
|
|
156
|
+
|
|
124
157
|
filter = [[SCContentFilter alloc] initWithDesktopIndependentWindow:targetWindow];
|
|
125
158
|
recordingWidth = (NSInteger)targetWindow.frame.size.width;
|
|
126
159
|
recordingHeight = (NSInteger)targetWindow.frame.size.height;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const MacRecorder = require('./index.js');
|
|
2
|
+
|
|
3
|
+
async function testCursorCoordinates() {
|
|
4
|
+
console.log('๐งช Testing cursor coordinate fixes for window recording...');
|
|
5
|
+
|
|
6
|
+
const recorder = new MacRecorder();
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
// Get available windows and displays
|
|
10
|
+
const windows = await recorder.getWindows();
|
|
11
|
+
const displays = await recorder.getDisplays();
|
|
12
|
+
|
|
13
|
+
console.log('\n๐ฑ Available displays:');
|
|
14
|
+
displays.forEach((display, i) => {
|
|
15
|
+
console.log(` ${i + 1}. Display ${display.id}: ${display.resolution} at (${display.x}, ${display.y}) ${display.isPrimary ? '(Primary)' : ''}`);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
console.log('\n๐ช Available windows:');
|
|
19
|
+
windows.slice(0, 5).forEach((window, i) => {
|
|
20
|
+
console.log(` ${i + 1}. ${window.title} (${window.app}) - ${window.width}x${window.height} at (${window.x}, ${window.y})`);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (windows.length === 0) {
|
|
24
|
+
console.log('โ No windows available for testing');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Pick the first available window for testing
|
|
29
|
+
const testWindow = windows[0];
|
|
30
|
+
console.log(`\n๐ฏ Testing with window: ${testWindow.title}`);
|
|
31
|
+
console.log(` Window position: (${testWindow.x}, ${testWindow.y})`);
|
|
32
|
+
console.log(` Window size: ${testWindow.width}x${testWindow.height}`);
|
|
33
|
+
|
|
34
|
+
// Check current cursor position before recording
|
|
35
|
+
const cursorPos = recorder.getCursorPosition();
|
|
36
|
+
console.log(`\n๐ฑ๏ธ Current cursor position (global): (${cursorPos.x}, ${cursorPos.y})`);
|
|
37
|
+
|
|
38
|
+
// Setup recording options for window recording
|
|
39
|
+
recorder.options.windowId = testWindow.id;
|
|
40
|
+
recorder.options.captureCursor = true;
|
|
41
|
+
|
|
42
|
+
console.log('\n๐ง Starting cursor capture test for window recording...');
|
|
43
|
+
|
|
44
|
+
// Start cursor capture with window-relative coordinates
|
|
45
|
+
const outputFile = `./test-output/cursor-test-window-${Date.now()}.json`;
|
|
46
|
+
|
|
47
|
+
// Start cursor tracking first to see if coordinate transformation works
|
|
48
|
+
await recorder.startCursorCapture(outputFile, {
|
|
49
|
+
windowRelative: true,
|
|
50
|
+
windowInfo: {
|
|
51
|
+
x: testWindow.x,
|
|
52
|
+
y: testWindow.y,
|
|
53
|
+
width: testWindow.width,
|
|
54
|
+
height: testWindow.height,
|
|
55
|
+
displayId: null // Let it auto-detect
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
console.log('โ
Cursor capture started successfully!');
|
|
60
|
+
console.log('๐ฑ๏ธ Move your mouse around the window for 5 seconds...');
|
|
61
|
+
console.log(` Window bounds: (0, 0) to (${testWindow.width}, ${testWindow.height})`);
|
|
62
|
+
|
|
63
|
+
// Wait for 5 seconds to capture cursor movements
|
|
64
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
65
|
+
|
|
66
|
+
console.log('\n๐ Stopping cursor capture...');
|
|
67
|
+
await recorder.stopCursorCapture();
|
|
68
|
+
|
|
69
|
+
console.log(`โ
Test completed! Check cursor data in: ${outputFile}`);
|
|
70
|
+
|
|
71
|
+
// Read and analyze some cursor data
|
|
72
|
+
const fs = require('fs');
|
|
73
|
+
if (fs.existsSync(outputFile)) {
|
|
74
|
+
const cursorData = JSON.parse(fs.readFileSync(outputFile, 'utf8'));
|
|
75
|
+
console.log(`\n๐ Captured ${cursorData.length} cursor events`);
|
|
76
|
+
|
|
77
|
+
if (cursorData.length > 0) {
|
|
78
|
+
const first = cursorData[0];
|
|
79
|
+
const last = cursorData[cursorData.length - 1];
|
|
80
|
+
|
|
81
|
+
console.log(` First event: (${first.x}, ${first.y}) - ${first.coordinateSystem}`);
|
|
82
|
+
console.log(` Last event: (${last.x}, ${last.y}) - ${last.coordinateSystem}`);
|
|
83
|
+
|
|
84
|
+
// Check if coordinates are within window bounds
|
|
85
|
+
const inBounds = cursorData.filter(event =>
|
|
86
|
+
event.x >= 0 && event.x < testWindow.width &&
|
|
87
|
+
event.y >= 0 && event.y < testWindow.height
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
console.log(` Events within window bounds: ${inBounds.length}/${cursorData.length} (${Math.round(inBounds.length/cursorData.length*100)}%)`);
|
|
91
|
+
|
|
92
|
+
if (inBounds.length > 0) {
|
|
93
|
+
console.log('โ
Cursor coordinates appear to be correctly transformed to window-relative!');
|
|
94
|
+
} else {
|
|
95
|
+
console.log('โ No cursor coordinates are within window bounds - transformation may be incorrect');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error('โ Test failed:', error.message);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
testCursorCoordinates().catch(console.error);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"x":758,"y":1089,"timestamp":37,"unixTimeMs":1758264693047,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":758,"y":1089,"timestamp":80,"unixTimeMs":1758264693090,"cursorType":"default","type":"mousedown","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":758,"y":1089,"timestamp":99,"unixTimeMs":1758264693109,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":758,"y":1089,"timestamp":180,"unixTimeMs":1758264693190,"cursorType":"default","type":"mouseup","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":758,"y":1089,"timestamp":201,"unixTimeMs":1758264693211,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":774,"y":1071,"timestamp":1610,"unixTimeMs":1758264694620,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":818,"y":1030,"timestamp":1631,"unixTimeMs":1758264694641,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":893,"y":972,"timestamp":1654,"unixTimeMs":1758264694664,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1015,"y":886,"timestamp":1677,"unixTimeMs":1758264694687,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1087,"y":843,"timestamp":1696,"unixTimeMs":1758264694706,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1233,"y":793,"timestamp":1714,"unixTimeMs":1758264694724,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1301,"y":776,"timestamp":1733,"unixTimeMs":1758264694743,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1360,"y":765,"timestamp":1755,"unixTimeMs":1758264694765,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1366,"y":764,"timestamp":1774,"unixTimeMs":1758264694784,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1363,"y":751,"timestamp":1814,"unixTimeMs":1758264694824,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1343,"y":709,"timestamp":1838,"unixTimeMs":1758264694848,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1335,"y":691,"timestamp":1855,"unixTimeMs":1758264694865,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1271,"y":583,"timestamp":1878,"unixTimeMs":1758264694888,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1250,"y":558,"timestamp":1898,"unixTimeMs":1758264694908,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1242,"y":552,"timestamp":1917,"unixTimeMs":1758264694927,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1238,"y":552,"timestamp":1937,"unixTimeMs":1758264694947,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1234,"y":554,"timestamp":1959,"unixTimeMs":1758264694969,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1233,"y":556,"timestamp":2207,"unixTimeMs":1758264695217,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1232,"y":559,"timestamp":2231,"unixTimeMs":1758264695241,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1232,"y":561,"timestamp":2252,"unixTimeMs":1758264695262,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1231,"y":565,"timestamp":2272,"unixTimeMs":1758264695282,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1231,"y":567,"timestamp":2290,"unixTimeMs":1758264695300,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1231,"y":595,"timestamp":2311,"unixTimeMs":1758264695321,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1236,"y":629,"timestamp":2330,"unixTimeMs":1758264695341,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1242,"y":647,"timestamp":2352,"unixTimeMs":1758264695362,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1251,"y":670,"timestamp":2369,"unixTimeMs":1758264695379,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1259,"y":702,"timestamp":2391,"unixTimeMs":1758264695401,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1265,"y":746,"timestamp":2409,"unixTimeMs":1758264695419,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1276,"y":763,"timestamp":2430,"unixTimeMs":1758264695440,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1272,"y":760,"timestamp":2985,"unixTimeMs":1758264695995,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1270,"y":758,"timestamp":3005,"unixTimeMs":1758264696015,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1269,"y":756,"timestamp":3047,"unixTimeMs":1758264696057,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1268,"y":754,"timestamp":3089,"unixTimeMs":1758264696099,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1268,"y":752,"timestamp":3132,"unixTimeMs":1758264696142,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1267,"y":750,"timestamp":3173,"unixTimeMs":1758264696183,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1266,"y":747,"timestamp":3215,"unixTimeMs":1758264696225,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1265,"y":745,"timestamp":3238,"unixTimeMs":1758264696248,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1263,"y":742,"timestamp":3278,"unixTimeMs":1758264696288,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1264,"y":740,"timestamp":3482,"unixTimeMs":1758264696492,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1266,"y":739,"timestamp":3522,"unixTimeMs":1758264696532,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1268,"y":738,"timestamp":3541,"unixTimeMs":1758264696551,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1277,"y":731,"timestamp":3563,"unixTimeMs":1758264696573,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1279,"y":730,"timestamp":3583,"unixTimeMs":1758264696593,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1281,"y":729,"timestamp":3688,"unixTimeMs":1758264696698,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1283,"y":727,"timestamp":3708,"unixTimeMs":1758264696718,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1286,"y":718,"timestamp":3873,"unixTimeMs":1758264696883,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1287,"y":713,"timestamp":3893,"unixTimeMs":1758264696903,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1289,"y":713,"timestamp":4204,"unixTimeMs":1758264697214,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}},{"x":1291,"y":713,"timestamp":4330,"unixTimeMs":1758264697340,"cursorType":"default","type":"move","coordinateSystem":"window-relative","windowInfo":{"width":3440,"height":1440,"displayId":null}}]
|