node-mac-recorder 2.22.19 → 2.22.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.
@@ -37,6 +37,16 @@ function shouldCaptureCursorSample(lastCapturedData, currentData) {
37
37
  return false;
38
38
  }
39
39
 
40
+ function appendCursorJsonLine(recorder, filepath, obj) {
41
+ const jsonString = JSON.stringify(obj);
42
+ if (recorder.cursorCaptureFirstWrite) {
43
+ fs.appendFileSync(filepath, jsonString);
44
+ recorder.cursorCaptureFirstWrite = false;
45
+ } else {
46
+ fs.appendFileSync(filepath, "," + jsonString);
47
+ }
48
+ }
49
+
40
50
  function packDisplayInfoForExport(di) {
41
51
  if (!di) return {};
42
52
  return {
@@ -95,28 +105,59 @@ function transformInputFrameGlobal(ifr, d) {
95
105
  };
96
106
  }
97
107
 
98
- function tryAppendSyntheticTextInputRow(recorder, filepath, cursorData, timestamp) {
108
+ /** @returns {boolean} Dosyaya textInput satırı yazıldı mı */
109
+ function tryAppendSyntheticTextInputRow(recorder, nativeBinding, filepath, cursorData, timestamp) {
99
110
  if (!IS_ELECTRON) {
100
- return;
111
+ return false;
101
112
  }
102
113
  const ct = cursorData.cursorType || "";
103
114
  if (ct !== "text" && ct !== "vertical-text") {
104
- return;
115
+ return false;
105
116
  }
106
117
  if (timestamp < ELECTRON_SYNTH_GRACE_MS) {
107
- return;
118
+ return false;
108
119
  }
109
120
  const wall = Date.now();
110
121
  if (
111
122
  wall - (recorder._electronSynthWallMs || 0) <
112
123
  ELECTRON_SYNTH_THROTTLE_MS
113
124
  ) {
114
- return;
125
+ return false;
115
126
  }
116
127
  const vx = cursorData.x;
117
128
  const vy = cursorData.y;
118
129
  if (!Number.isFinite(vx) || !Number.isFinite(vy)) {
119
- return;
130
+ return false;
131
+ }
132
+
133
+ // Gerçek caret pozisyonunu accessibility API'den al
134
+ let caretX = vx;
135
+ let caretY = vy;
136
+ let inputFrame = { x: vx - 1, y: vy - 9, width: 2, height: 18 };
137
+ let hasRealCaret = false;
138
+
139
+ if (nativeBinding && typeof nativeBinding.getTextInputSnapshot === "function") {
140
+ try {
141
+ const snap = nativeBinding.getTextInputSnapshot();
142
+ if (
143
+ snap &&
144
+ Number.isFinite(snap.caretX) &&
145
+ Number.isFinite(snap.caretY)
146
+ ) {
147
+ // Global koordinatları video uzayına dönüştür
148
+ const d = recorder.cursorDisplayInfo;
149
+ const caretT = transformGlobalToVideo(snap.caretX, snap.caretY, d);
150
+ caretX = caretT.x;
151
+ caretY = caretT.y;
152
+ hasRealCaret = true;
153
+
154
+ if (snap.inputFrame) {
155
+ inputFrame = transformInputFrameGlobal(snap.inputFrame, d);
156
+ }
157
+ }
158
+ } catch {
159
+ // AX API hata verirse cursor pozisyonuna fallback
160
+ }
120
161
  }
121
162
 
122
163
  const tiRow = {
@@ -126,15 +167,12 @@ function tryAppendSyntheticTextInputRow(recorder, filepath, cursorData, timestam
126
167
  unixTimeMs: wall,
127
168
  cursorType: "text",
128
169
  type: "textInput",
129
- caretX: vx,
130
- caretY: vy,
131
- inputFrame: {
132
- x: vx - 1,
133
- y: vy - 9,
134
- width: 2,
135
- height: 18,
136
- },
137
- coordinateSystem: cursorData.coordinateSystem,
170
+ caretX,
171
+ caretY,
172
+ inputFrame,
173
+ coordinateSystem: hasRealCaret
174
+ ? (recorder.cursorDisplayInfo?.videoRelative ? "video-relative" : "global")
175
+ : cursorData.coordinateSystem,
138
176
  recordingType: cursorData.recordingType,
139
177
  videoInfo: cursorData.videoInfo || {},
140
178
  displayInfo: cursorData.displayInfo || {},
@@ -167,7 +205,7 @@ function tryAppendSyntheticTextInputRow(recorder, filepath, cursorData, timestam
167
205
  Math.abs(le.caretY - tiRow.caretY) < 0.75 &&
168
206
  timestamp - le.timestamp < 220
169
207
  ) {
170
- return;
208
+ return false;
171
209
  }
172
210
  recorder._lastTextInputEmitted = {
173
211
  caretX: tiRow.caretX,
@@ -176,13 +214,8 @@ function tryAppendSyntheticTextInputRow(recorder, filepath, cursorData, timestam
176
214
  };
177
215
  recorder._electronSynthWallMs = wall;
178
216
 
179
- const jsonString = JSON.stringify(tiRow);
180
- if (recorder.cursorCaptureFirstWrite) {
181
- fs.appendFileSync(filepath, jsonString);
182
- recorder.cursorCaptureFirstWrite = false;
183
- } else {
184
- fs.appendFileSync(filepath, "," + jsonString);
185
- }
217
+ appendCursorJsonLine(recorder, filepath, tiRow);
218
+ return true;
186
219
  }
187
220
 
188
221
  function tryAppendTextInput(
@@ -501,24 +534,25 @@ async function startCursorCapture(recorder, nativeBinding, intervalOrFilepath, o
501
534
  };
502
535
  }
503
536
 
537
+ let wroteMoveSample = false;
504
538
  if (shouldCaptureCursorSample(recorder.lastCapturedData, cursorData)) {
505
- const jsonString = JSON.stringify(cursorData);
506
- if (recorder.cursorCaptureFirstWrite) {
507
- fs.appendFileSync(filepath, jsonString);
508
- recorder.cursorCaptureFirstWrite = false;
509
- } else {
510
- fs.appendFileSync(filepath, "," + jsonString);
511
- }
539
+ appendCursorJsonLine(recorder, filepath, cursorData);
512
540
  recorder.lastCapturedData = { ...cursorData };
541
+ wroteMoveSample = true;
513
542
  }
514
543
 
515
544
  if (IS_ELECTRON) {
516
- tryAppendSyntheticTextInputRow(
545
+ const textInputWritten = tryAppendSyntheticTextInputRow(
517
546
  recorder,
547
+ nativeBinding,
518
548
  filepath,
519
549
  cursorData,
520
550
  timestamp,
521
551
  );
552
+ if (textInputWritten && !wroteMoveSample) {
553
+ appendCursorJsonLine(recorder, filepath, cursorData);
554
+ recorder.lastCapturedData = { ...cursorData };
555
+ }
522
556
  } else {
523
557
  queueDeferredTextInputSample(
524
558
  recorder,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.22.19",
3
+ "version": "2.22.21",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [