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 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 global โ†’ window-relative coordinates
834
- x = position.x - this.cursorDisplayInfo.x;
835
- y = position.y - this.cursorDisplayInfo.y;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.17.15",
3
+ "version": "2.17.16",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -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}}]