node-mac-recorder 2.22.17 → 2.22.18

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.
@@ -9,9 +9,13 @@ const IS_ELECTRON = !!(
9
9
  process.versions.electron
10
10
  );
11
11
 
12
- const TEXT_INPUT_SAMPLE_MS = IS_ELECTRON ? 280 : 95;
12
+ const NATIVE_TEXT_INPUT_SAMPLE_MS = 120;
13
+ const NATIVE_TEXT_INPUT_GRACE_MS = 600;
13
14
 
14
- const TEXT_INPUT_GRACE_MS = IS_ELECTRON ? 3200 : 600;
15
+ const ELECTRON_SYNTH_GRACE_MS = 400;
16
+ const ELECTRON_SYNTH_THROTTLE_MS = 220;
17
+
18
+ const DEFAULT_CURSOR_INTERVAL_MS = IS_ELECTRON ? 50 : 20;
15
19
 
16
20
  function shouldCaptureCursorSample(lastCapturedData, currentData) {
17
21
  if (!lastCapturedData) {
@@ -76,6 +80,96 @@ function transformInputFrameGlobal(ifr, d) {
76
80
  };
77
81
  }
78
82
 
83
+ function tryAppendSyntheticTextInputRow(recorder, filepath, cursorData, timestamp) {
84
+ if (!IS_ELECTRON) {
85
+ return;
86
+ }
87
+ const ct = cursorData.cursorType || "";
88
+ if (ct !== "text" && ct !== "vertical-text") {
89
+ return;
90
+ }
91
+ if (timestamp < ELECTRON_SYNTH_GRACE_MS) {
92
+ return;
93
+ }
94
+ const wall = Date.now();
95
+ if (
96
+ wall - (recorder._electronSynthWallMs || 0) <
97
+ ELECTRON_SYNTH_THROTTLE_MS
98
+ ) {
99
+ return;
100
+ }
101
+ const vx = cursorData.x;
102
+ const vy = cursorData.y;
103
+ if (!Number.isFinite(vx) || !Number.isFinite(vy)) {
104
+ return;
105
+ }
106
+
107
+ const tiRow = {
108
+ x: vx,
109
+ y: vy,
110
+ timestamp,
111
+ unixTimeMs: wall,
112
+ cursorType: "text",
113
+ type: "textInput",
114
+ caretX: vx,
115
+ caretY: vy,
116
+ inputFrame: {
117
+ x: vx - 1,
118
+ y: vy - 9,
119
+ width: 2,
120
+ height: 18,
121
+ },
122
+ coordinateSystem: cursorData.coordinateSystem,
123
+ recordingType: cursorData.recordingType,
124
+ videoInfo: cursorData.videoInfo || {},
125
+ displayInfo: cursorData.displayInfo || {},
126
+ };
127
+
128
+ if (cursorData.location) {
129
+ tiRow.location = cursorData.location;
130
+ }
131
+ if (cursorData.windowRelative) {
132
+ tiRow.windowRelative = cursorData.windowRelative;
133
+ }
134
+
135
+ if (
136
+ recorder.cursorCaptureFirstWrite &&
137
+ recorder.cursorCaptureSessionTimestamp
138
+ ) {
139
+ tiRow._syncMetadata = {
140
+ videoStartTime: recorder.cursorCaptureSessionTimestamp,
141
+ cursorStartTime: recorder.cursorCaptureStartTime,
142
+ offsetMs:
143
+ recorder.cursorCaptureStartTime -
144
+ recorder.cursorCaptureSessionTimestamp,
145
+ };
146
+ }
147
+
148
+ const le = recorder._lastTextInputEmitted;
149
+ if (
150
+ le &&
151
+ Math.abs(le.caretX - tiRow.caretX) < 0.75 &&
152
+ Math.abs(le.caretY - tiRow.caretY) < 0.75 &&
153
+ timestamp - le.timestamp < 220
154
+ ) {
155
+ return;
156
+ }
157
+ recorder._lastTextInputEmitted = {
158
+ caretX: tiRow.caretX,
159
+ caretY: tiRow.caretY,
160
+ timestamp,
161
+ };
162
+ recorder._electronSynthWallMs = wall;
163
+
164
+ const jsonString = JSON.stringify(tiRow);
165
+ if (recorder.cursorCaptureFirstWrite) {
166
+ fs.appendFileSync(filepath, jsonString);
167
+ recorder.cursorCaptureFirstWrite = false;
168
+ } else {
169
+ fs.appendFileSync(filepath, "," + jsonString);
170
+ }
171
+ }
172
+
79
173
  function tryAppendTextInput(
80
174
  recorder,
81
175
  nativeBinding,
@@ -83,10 +177,13 @@ function tryAppendTextInput(
83
177
  position,
84
178
  timestamp,
85
179
  ) {
180
+ if (IS_ELECTRON) {
181
+ return;
182
+ }
86
183
  if (typeof nativeBinding.getTextInputSnapshot !== "function") {
87
184
  return;
88
185
  }
89
- if (timestamp < TEXT_INPUT_GRACE_MS) {
186
+ if (timestamp < NATIVE_TEXT_INPUT_GRACE_MS) {
90
187
  return;
91
188
  }
92
189
  const ct = position.cursorType || "";
@@ -94,7 +191,10 @@ function tryAppendTextInput(
94
191
  return;
95
192
  }
96
193
  const wall = Date.now();
97
- if (wall - (recorder._tiSampleWallMs || 0) < TEXT_INPUT_SAMPLE_MS) {
194
+ if (
195
+ wall - (recorder._tiSampleWallMs || 0) <
196
+ NATIVE_TEXT_INPUT_SAMPLE_MS
197
+ ) {
98
198
  return;
99
199
  }
100
200
  recorder._tiSampleWallMs = wall;
@@ -194,10 +294,13 @@ function queueDeferredTextInputSample(
194
294
  position,
195
295
  timestamp,
196
296
  ) {
297
+ if (IS_ELECTRON) {
298
+ return;
299
+ }
197
300
  if (typeof nativeBinding.getTextInputSnapshot !== "function") {
198
301
  return;
199
302
  }
200
- if (timestamp < TEXT_INPUT_GRACE_MS) {
303
+ if (timestamp < NATIVE_TEXT_INPUT_GRACE_MS) {
201
304
  return;
202
305
  }
203
306
  const ct = position.cursorType || "";
@@ -230,7 +333,7 @@ function queueDeferredTextInputSample(
230
333
 
231
334
  async function startCursorCapture(recorder, nativeBinding, intervalOrFilepath, options = {}) {
232
335
  let filepath;
233
- let interval = 20;
336
+ let interval = DEFAULT_CURSOR_INTERVAL_MS;
234
337
 
235
338
  if (typeof intervalOrFilepath === "number") {
236
339
  interval = Math.max(10, intervalOrFilepath);
@@ -283,6 +386,7 @@ async function startCursorCapture(recorder, nativeBinding, intervalOrFilepath, o
283
386
  recorder.lastCapturedData = null;
284
387
  recorder.cursorCaptureSessionTimestamp = recorder.sessionTimestamp;
285
388
  recorder._tiSampleWallMs = 0;
389
+ recorder._electronSynthWallMs = 0;
286
390
  recorder._lastTextInputEmitted = null;
287
391
  recorder._tiDeferredPending = false;
288
392
 
@@ -405,13 +509,22 @@ async function startCursorCapture(recorder, nativeBinding, intervalOrFilepath, o
405
509
  recorder.lastCapturedData = { ...cursorData };
406
510
  }
407
511
 
408
- queueDeferredTextInputSample(
409
- recorder,
410
- nativeBinding,
411
- filepath,
412
- position,
413
- timestamp,
414
- );
512
+ if (IS_ELECTRON) {
513
+ tryAppendSyntheticTextInputRow(
514
+ recorder,
515
+ filepath,
516
+ cursorData,
517
+ timestamp,
518
+ );
519
+ } else {
520
+ queueDeferredTextInputSample(
521
+ recorder,
522
+ nativeBinding,
523
+ filepath,
524
+ position,
525
+ timestamp,
526
+ );
527
+ }
415
528
  } catch (error) {
416
529
  console.error("Cursor capture error:", error);
417
530
  }
@@ -444,6 +557,7 @@ async function stopCursorCapture(recorder) {
444
557
  recorder.cursorCaptureFirstWrite = true;
445
558
  recorder.cursorDisplayInfo = null;
446
559
  recorder._tiSampleWallMs = 0;
560
+ recorder._electronSynthWallMs = 0;
447
561
  recorder._lastTextInputEmitted = null;
448
562
  recorder._tiDeferredPending = false;
449
563
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.22.17",
3
+ "version": "2.22.18",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [