node-mac-recorder 1.2.6 → 1.2.8
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/cursor-data-1751364226346.json +1 -0
- package/cursor-data-1751364314136.json +1 -0
- package/index.js +202 -7
- package/package.json +1 -1
- package/src/cursor_tracker.mm +12 -23
- package/cursor-data.json +0 -359
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|
package/index.js
CHANGED
|
@@ -32,6 +32,8 @@ class MacRecorder extends EventEmitter {
|
|
|
32
32
|
this.cursorCaptureStartTime = null;
|
|
33
33
|
this.cursorCaptureFirstWrite = true;
|
|
34
34
|
this.lastCapturedData = null;
|
|
35
|
+
this.cursorDisplayInfo = null;
|
|
36
|
+
this.recordingDisplayInfo = null;
|
|
35
37
|
|
|
36
38
|
this.options = {
|
|
37
39
|
includeMicrophone: false, // Default olarak mikrofon kapalı
|
|
@@ -44,6 +46,13 @@ class MacRecorder extends EventEmitter {
|
|
|
44
46
|
displayId: null, // Hangi ekranı kaydedeceği (null = ana ekran)
|
|
45
47
|
windowId: null, // Hangi pencereyi kaydedeceği (null = tam ekran)
|
|
46
48
|
};
|
|
49
|
+
|
|
50
|
+
// Display cache için async initialization
|
|
51
|
+
this.cachedDisplays = null;
|
|
52
|
+
this.refreshDisplayCache();
|
|
53
|
+
|
|
54
|
+
// Native cursor warm-up (cold start delay'ini önlemek için)
|
|
55
|
+
this.warmUpCursor();
|
|
47
56
|
}
|
|
48
57
|
|
|
49
58
|
/**
|
|
@@ -189,6 +198,16 @@ class MacRecorder extends EventEmitter {
|
|
|
189
198
|
// DisplayId'yi ayarla
|
|
190
199
|
if (targetDisplayId !== null) {
|
|
191
200
|
this.options.displayId = targetDisplayId;
|
|
201
|
+
|
|
202
|
+
// Recording için display bilgisini sakla (cursor capture için)
|
|
203
|
+
const targetDisplay = displays[targetDisplayId];
|
|
204
|
+
this.recordingDisplayInfo = {
|
|
205
|
+
displayId: targetDisplayId,
|
|
206
|
+
x: targetDisplay.x,
|
|
207
|
+
y: targetDisplay.y,
|
|
208
|
+
width: parseInt(targetDisplay.resolution.split("x")[0]),
|
|
209
|
+
height: parseInt(targetDisplay.resolution.split("x")[1]),
|
|
210
|
+
};
|
|
192
211
|
}
|
|
193
212
|
|
|
194
213
|
this.options.captureArea = {
|
|
@@ -210,6 +229,25 @@ class MacRecorder extends EventEmitter {
|
|
|
210
229
|
}
|
|
211
230
|
}
|
|
212
231
|
|
|
232
|
+
// DisplayId manuel ayarlanmışsa display bilgisini sakla
|
|
233
|
+
if (this.options.displayId !== null && !this.recordingDisplayInfo) {
|
|
234
|
+
try {
|
|
235
|
+
const displays = await this.getDisplays();
|
|
236
|
+
if (this.options.displayId < displays.length) {
|
|
237
|
+
const targetDisplay = displays[this.options.displayId];
|
|
238
|
+
this.recordingDisplayInfo = {
|
|
239
|
+
displayId: this.options.displayId,
|
|
240
|
+
x: targetDisplay.x,
|
|
241
|
+
y: targetDisplay.y,
|
|
242
|
+
width: parseInt(targetDisplay.resolution.split("x")[0]),
|
|
243
|
+
height: parseInt(targetDisplay.resolution.split("x")[1]),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
} catch (error) {
|
|
247
|
+
console.warn("Display bilgisi alınamadı:", error.message);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
213
251
|
// Çıkış dizinini oluştur
|
|
214
252
|
const outputDir = path.dirname(outputPath);
|
|
215
253
|
if (!fs.existsSync(outputDir)) {
|
|
@@ -291,6 +329,7 @@ class MacRecorder extends EventEmitter {
|
|
|
291
329
|
}
|
|
292
330
|
|
|
293
331
|
this.isRecording = false;
|
|
332
|
+
this.recordingDisplayInfo = null;
|
|
294
333
|
|
|
295
334
|
const result = {
|
|
296
335
|
code: success ? 0 : 1,
|
|
@@ -311,6 +350,7 @@ class MacRecorder extends EventEmitter {
|
|
|
311
350
|
resolve(result);
|
|
312
351
|
} catch (error) {
|
|
313
352
|
this.isRecording = false;
|
|
353
|
+
this.recordingDisplayInfo = null;
|
|
314
354
|
if (this.recordingTimer) {
|
|
315
355
|
clearInterval(this.recordingTimer);
|
|
316
356
|
this.recordingTimer = null;
|
|
@@ -458,16 +498,52 @@ class MacRecorder extends EventEmitter {
|
|
|
458
498
|
|
|
459
499
|
/**
|
|
460
500
|
* Cursor capture başlatır - otomatik olarak dosyaya yazmaya başlar
|
|
501
|
+
* Recording başlatılmışsa otomatik olarak display-relative koordinatlar kullanır
|
|
502
|
+
* @param {string} filepath - Cursor data JSON dosya yolu
|
|
461
503
|
*/
|
|
462
|
-
async startCursorCapture(
|
|
463
|
-
|
|
464
|
-
|
|
504
|
+
async startCursorCapture(intervalOrFilepath = 100) {
|
|
505
|
+
let filepath;
|
|
506
|
+
let interval = 20; // Default 50 FPS
|
|
507
|
+
|
|
508
|
+
// Parameter parsing: number = interval, string = filepath
|
|
509
|
+
if (typeof intervalOrFilepath === "number") {
|
|
510
|
+
interval = Math.max(10, intervalOrFilepath); // Min 10ms
|
|
511
|
+
filepath = `cursor-data-${Date.now()}.json`;
|
|
512
|
+
} else if (typeof intervalOrFilepath === "string") {
|
|
513
|
+
filepath = intervalOrFilepath;
|
|
514
|
+
} else {
|
|
515
|
+
throw new Error(
|
|
516
|
+
"Parameter must be interval (number) or filepath (string)"
|
|
517
|
+
);
|
|
465
518
|
}
|
|
466
519
|
|
|
467
520
|
if (this.cursorCaptureInterval) {
|
|
468
521
|
throw new Error("Cursor capture is already running");
|
|
469
522
|
}
|
|
470
523
|
|
|
524
|
+
// Recording başlatılmışsa o display'i kullan, yoksa main display kullan
|
|
525
|
+
if (this.recordingDisplayInfo) {
|
|
526
|
+
this.cursorDisplayInfo = this.recordingDisplayInfo;
|
|
527
|
+
} else {
|
|
528
|
+
// Main display bilgisini al (her zaman relative koordinatlar için)
|
|
529
|
+
try {
|
|
530
|
+
const displays = await this.getDisplays();
|
|
531
|
+
const mainDisplay = displays.find((d) => d.isPrimary) || displays[0];
|
|
532
|
+
if (mainDisplay) {
|
|
533
|
+
this.cursorDisplayInfo = {
|
|
534
|
+
displayId: 0,
|
|
535
|
+
x: mainDisplay.x,
|
|
536
|
+
y: mainDisplay.y,
|
|
537
|
+
width: parseInt(mainDisplay.resolution.split("x")[0]),
|
|
538
|
+
height: parseInt(mainDisplay.resolution.split("x")[1]),
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
} catch (error) {
|
|
542
|
+
console.warn("Main display bilgisi alınamadı:", error.message);
|
|
543
|
+
this.cursorDisplayInfo = null; // Fallback: global koordinatlar
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
471
547
|
return new Promise((resolve, reject) => {
|
|
472
548
|
try {
|
|
473
549
|
// Dosyayı oluştur ve temizle
|
|
@@ -485,9 +561,29 @@ class MacRecorder extends EventEmitter {
|
|
|
485
561
|
const position = nativeBinding.getCursorPosition();
|
|
486
562
|
const timestamp = Date.now() - this.cursorCaptureStartTime;
|
|
487
563
|
|
|
564
|
+
// Global koordinatları display-relative'e çevir
|
|
565
|
+
let x = position.x;
|
|
566
|
+
let y = position.y;
|
|
567
|
+
|
|
568
|
+
if (this.cursorDisplayInfo) {
|
|
569
|
+
// Display offset'lerini çıkar
|
|
570
|
+
x = position.x - this.cursorDisplayInfo.x;
|
|
571
|
+
y = position.y - this.cursorDisplayInfo.y;
|
|
572
|
+
|
|
573
|
+
// Display bounds kontrolü - cursor display dışındaysa kaydetme
|
|
574
|
+
if (
|
|
575
|
+
x < 0 ||
|
|
576
|
+
y < 0 ||
|
|
577
|
+
x >= this.cursorDisplayInfo.width ||
|
|
578
|
+
y >= this.cursorDisplayInfo.height
|
|
579
|
+
) {
|
|
580
|
+
return; // Bu frame'i skip et
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
488
584
|
const cursorData = {
|
|
489
|
-
x:
|
|
490
|
-
y:
|
|
585
|
+
x: x,
|
|
586
|
+
y: y,
|
|
491
587
|
timestamp: timestamp,
|
|
492
588
|
cursorType: position.cursorType,
|
|
493
589
|
type: position.eventType || "move",
|
|
@@ -511,7 +607,7 @@ class MacRecorder extends EventEmitter {
|
|
|
511
607
|
} catch (error) {
|
|
512
608
|
console.error("Cursor capture error:", error);
|
|
513
609
|
}
|
|
514
|
-
},
|
|
610
|
+
}, interval); // Configurable FPS
|
|
515
611
|
|
|
516
612
|
this.emit("cursorCaptureStarted", filepath);
|
|
517
613
|
resolve(true);
|
|
@@ -546,6 +642,7 @@ class MacRecorder extends EventEmitter {
|
|
|
546
642
|
this.lastCapturedData = null;
|
|
547
643
|
this.cursorCaptureStartTime = null;
|
|
548
644
|
this.cursorCaptureFirstWrite = true;
|
|
645
|
+
this.cursorDisplayInfo = null;
|
|
549
646
|
|
|
550
647
|
this.emit("cursorCaptureStopped");
|
|
551
648
|
resolve(true);
|
|
@@ -557,15 +654,112 @@ class MacRecorder extends EventEmitter {
|
|
|
557
654
|
|
|
558
655
|
/**
|
|
559
656
|
* Anlık cursor pozisyonunu ve tipini döndürür
|
|
657
|
+
* Display-relative koordinatlar döner (her zaman pozitif)
|
|
560
658
|
*/
|
|
561
659
|
getCursorPosition() {
|
|
562
660
|
try {
|
|
563
|
-
|
|
661
|
+
const position = nativeBinding.getCursorPosition();
|
|
662
|
+
|
|
663
|
+
// Cursor hangi display'de ise o display'e relative döndür
|
|
664
|
+
return this.getDisplayRelativePositionSync(position);
|
|
564
665
|
} catch (error) {
|
|
565
666
|
throw new Error("Failed to get cursor position: " + error.message);
|
|
566
667
|
}
|
|
567
668
|
}
|
|
568
669
|
|
|
670
|
+
/**
|
|
671
|
+
* Global koordinatları en uygun display'e relative çevirir (sync version)
|
|
672
|
+
*/
|
|
673
|
+
getDisplayRelativePositionSync(position) {
|
|
674
|
+
try {
|
|
675
|
+
// Cache'lenmiş displays'leri kullan
|
|
676
|
+
if (!this.cachedDisplays) {
|
|
677
|
+
// İlk çağrı - global koordinat döndür ve cache başlat
|
|
678
|
+
this.refreshDisplayCache();
|
|
679
|
+
return position;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// Cursor hangi display içinde ise onu bul
|
|
683
|
+
for (const display of this.cachedDisplays) {
|
|
684
|
+
const x = parseInt(display.x);
|
|
685
|
+
const y = parseInt(display.y);
|
|
686
|
+
const width = parseInt(display.resolution.split("x")[0]);
|
|
687
|
+
const height = parseInt(display.resolution.split("x")[1]);
|
|
688
|
+
|
|
689
|
+
if (
|
|
690
|
+
position.x >= x &&
|
|
691
|
+
position.x < x + width &&
|
|
692
|
+
position.y >= y &&
|
|
693
|
+
position.y < y + height
|
|
694
|
+
) {
|
|
695
|
+
// Bu display içinde
|
|
696
|
+
return {
|
|
697
|
+
x: position.x - x,
|
|
698
|
+
y: position.y - y,
|
|
699
|
+
cursorType: position.cursorType,
|
|
700
|
+
eventType: position.eventType,
|
|
701
|
+
displayId: display.id,
|
|
702
|
+
displayIndex: this.cachedDisplays.indexOf(display),
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Hiçbir display'de değilse main display'e relative döndür
|
|
708
|
+
const mainDisplay =
|
|
709
|
+
this.cachedDisplays.find((d) => d.isPrimary) || this.cachedDisplays[0];
|
|
710
|
+
if (mainDisplay) {
|
|
711
|
+
return {
|
|
712
|
+
x: position.x - parseInt(mainDisplay.x),
|
|
713
|
+
y: position.y - parseInt(mainDisplay.y),
|
|
714
|
+
cursorType: position.cursorType,
|
|
715
|
+
eventType: position.eventType,
|
|
716
|
+
displayId: mainDisplay.id,
|
|
717
|
+
displayIndex: this.cachedDisplays.indexOf(mainDisplay),
|
|
718
|
+
outsideDisplay: true,
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// Fallback: global koordinat
|
|
723
|
+
return position;
|
|
724
|
+
} catch (error) {
|
|
725
|
+
// Hata durumunda global koordinat döndür
|
|
726
|
+
return position;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Display cache'ini refresh eder
|
|
732
|
+
*/
|
|
733
|
+
async refreshDisplayCache() {
|
|
734
|
+
try {
|
|
735
|
+
this.cachedDisplays = await this.getDisplays();
|
|
736
|
+
} catch (error) {
|
|
737
|
+
console.warn("Display cache refresh failed:", error.message);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* Native cursor modülünü warm-up yapar (cold start delay'ini önler)
|
|
743
|
+
*/
|
|
744
|
+
warmUpCursor() {
|
|
745
|
+
// Async warm-up to prevent blocking constructor
|
|
746
|
+
setTimeout(() => {
|
|
747
|
+
try {
|
|
748
|
+
// Silent warm-up call
|
|
749
|
+
nativeBinding.getCursorPosition();
|
|
750
|
+
} catch (error) {
|
|
751
|
+
// Ignore warm-up errors
|
|
752
|
+
}
|
|
753
|
+
}, 10); // 10ms delay to not block initialization
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* getCurrentCursorPosition alias for getCursorPosition (backward compatibility)
|
|
758
|
+
*/
|
|
759
|
+
getCurrentCursorPosition() {
|
|
760
|
+
return this.getCursorPosition();
|
|
761
|
+
}
|
|
762
|
+
|
|
569
763
|
/**
|
|
570
764
|
* Cursor capture durumunu döndürür
|
|
571
765
|
*/
|
|
@@ -574,6 +768,7 @@ class MacRecorder extends EventEmitter {
|
|
|
574
768
|
isCapturing: !!this.cursorCaptureInterval,
|
|
575
769
|
outputFile: this.cursorCaptureFile || null,
|
|
576
770
|
startTime: this.cursorCaptureStartTime || null,
|
|
771
|
+
displayInfo: this.cursorDisplayInfo || null,
|
|
577
772
|
};
|
|
578
773
|
}
|
|
579
774
|
|
package/package.json
CHANGED
package/src/cursor_tracker.mm
CHANGED
|
@@ -251,22 +251,13 @@ void cursorTimerCallback() {
|
|
|
251
251
|
return;
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
-
//
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
mouseLocation = [NSEvent mouseLocation];
|
|
260
|
-
} else {
|
|
261
|
-
dispatch_sync(dispatch_get_main_queue(), ^{
|
|
262
|
-
mouseLocation = [NSEvent mouseLocation];
|
|
263
|
-
});
|
|
254
|
+
// CGEventGetLocation direkt global koordinat verir - çoklu ekran desteği için daha doğru
|
|
255
|
+
CGEventRef event = CGEventCreate(NULL);
|
|
256
|
+
CGPoint location = CGEventGetLocation(event);
|
|
257
|
+
if (event) {
|
|
258
|
+
CFRelease(event);
|
|
264
259
|
}
|
|
265
260
|
|
|
266
|
-
CGDirectDisplayID mainDisplay = CGMainDisplayID();
|
|
267
|
-
size_t displayHeight = CGDisplayPixelsHigh(mainDisplay);
|
|
268
|
-
location = CGPointMake(mouseLocation.x, displayHeight - mouseLocation.y);
|
|
269
|
-
|
|
270
261
|
NSTimeInterval timestamp = [[NSDate date] timeIntervalSinceDate:g_trackingStartTime] * 1000; // milliseconds
|
|
271
262
|
NSString *cursorType = getCursorType();
|
|
272
263
|
|
|
@@ -443,15 +434,13 @@ Napi::Value GetCursorPosition(const Napi::CallbackInfo& info) {
|
|
|
443
434
|
Napi::Env env = info.Env();
|
|
444
435
|
|
|
445
436
|
@try {
|
|
446
|
-
// NSEvent
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
// macOS coordinate system (bottom-left origin) to screen coordinates (top-left origin)
|
|
454
|
-
CGPoint location = CGPointMake(mouseLocation.x, displayHeight - mouseLocation.y);
|
|
437
|
+
// NSEvent mouseLocation zaten global koordinatlarda (all displays combined)
|
|
438
|
+
// CGEventGetLocation kullanarak direkt global koordinat al - daha doğru
|
|
439
|
+
CGEventRef event = CGEventCreate(NULL);
|
|
440
|
+
CGPoint location = CGEventGetLocation(event);
|
|
441
|
+
if (event) {
|
|
442
|
+
CFRelease(event);
|
|
443
|
+
}
|
|
455
444
|
|
|
456
445
|
NSString *cursorType = getCursorType();
|
|
457
446
|
|
package/cursor-data.json
DELETED
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"x": 1947,
|
|
4
|
-
"y": 780,
|
|
5
|
-
"timestamp": 85,
|
|
6
|
-
"cursorType": "pointer",
|
|
7
|
-
"type": "move"
|
|
8
|
-
},
|
|
9
|
-
{
|
|
10
|
-
"x": 1950,
|
|
11
|
-
"y": 780,
|
|
12
|
-
"timestamp": 1476,
|
|
13
|
-
"cursorType": "pointer",
|
|
14
|
-
"type": "move"
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
"x": 1954,
|
|
18
|
-
"y": 778,
|
|
19
|
-
"timestamp": 1500,
|
|
20
|
-
"cursorType": "pointer",
|
|
21
|
-
"type": "move"
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"x": 1958,
|
|
25
|
-
"y": 777,
|
|
26
|
-
"timestamp": 1518,
|
|
27
|
-
"cursorType": "pointer",
|
|
28
|
-
"type": "move"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"x": 1963,
|
|
32
|
-
"y": 775,
|
|
33
|
-
"timestamp": 1541,
|
|
34
|
-
"cursorType": "pointer",
|
|
35
|
-
"type": "move"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"x": 1967,
|
|
39
|
-
"y": 775,
|
|
40
|
-
"timestamp": 1595,
|
|
41
|
-
"cursorType": "default",
|
|
42
|
-
"type": "move"
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
"x": 1971,
|
|
46
|
-
"y": 775,
|
|
47
|
-
"timestamp": 1596,
|
|
48
|
-
"cursorType": "default",
|
|
49
|
-
"type": "move"
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
"x": 1973,
|
|
53
|
-
"y": 775,
|
|
54
|
-
"timestamp": 1617,
|
|
55
|
-
"cursorType": "default",
|
|
56
|
-
"type": "move"
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
"x": 1975,
|
|
60
|
-
"y": 775,
|
|
61
|
-
"timestamp": 1659,
|
|
62
|
-
"cursorType": "default",
|
|
63
|
-
"type": "move"
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
"x": 1977,
|
|
67
|
-
"y": 775,
|
|
68
|
-
"timestamp": 1679,
|
|
69
|
-
"cursorType": "pointer",
|
|
70
|
-
"type": "move"
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
"x": 1979,
|
|
74
|
-
"y": 775,
|
|
75
|
-
"timestamp": 1744,
|
|
76
|
-
"cursorType": "pointer",
|
|
77
|
-
"type": "move"
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
"x": 1979,
|
|
81
|
-
"y": 777,
|
|
82
|
-
"timestamp": 1807,
|
|
83
|
-
"cursorType": "pointer",
|
|
84
|
-
"type": "move"
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
"x": 1973,
|
|
88
|
-
"y": 782,
|
|
89
|
-
"timestamp": 1828,
|
|
90
|
-
"cursorType": "default",
|
|
91
|
-
"type": "move"
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
"x": 1968,
|
|
95
|
-
"y": 787,
|
|
96
|
-
"timestamp": 1850,
|
|
97
|
-
"cursorType": "default",
|
|
98
|
-
"type": "move"
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
"x": 1957,
|
|
102
|
-
"y": 793,
|
|
103
|
-
"timestamp": 1868,
|
|
104
|
-
"cursorType": "pointer",
|
|
105
|
-
"type": "move"
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
"x": 1948,
|
|
109
|
-
"y": 799,
|
|
110
|
-
"timestamp": 1891,
|
|
111
|
-
"cursorType": "pointer",
|
|
112
|
-
"type": "move"
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
"x": 1943,
|
|
116
|
-
"y": 802,
|
|
117
|
-
"timestamp": 1911,
|
|
118
|
-
"cursorType": "default",
|
|
119
|
-
"type": "move"
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
"x": 1937,
|
|
123
|
-
"y": 804,
|
|
124
|
-
"timestamp": 1933,
|
|
125
|
-
"cursorType": "default",
|
|
126
|
-
"type": "move"
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
"x": 1938,
|
|
130
|
-
"y": 800,
|
|
131
|
-
"timestamp": 2309,
|
|
132
|
-
"cursorType": "default",
|
|
133
|
-
"type": "move"
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
"x": 1939,
|
|
137
|
-
"y": 799,
|
|
138
|
-
"timestamp": 2329,
|
|
139
|
-
"cursorType": "pointer",
|
|
140
|
-
"type": "move"
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
"x": 1940,
|
|
144
|
-
"y": 797,
|
|
145
|
-
"timestamp": 2435,
|
|
146
|
-
"cursorType": "pointer",
|
|
147
|
-
"type": "move"
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
"x": 1941,
|
|
151
|
-
"y": 794,
|
|
152
|
-
"timestamp": 2477,
|
|
153
|
-
"cursorType": "pointer",
|
|
154
|
-
"type": "move"
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
"x": 1941,
|
|
158
|
-
"y": 792,
|
|
159
|
-
"timestamp": 2500,
|
|
160
|
-
"cursorType": "pointer",
|
|
161
|
-
"type": "move"
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
"x": 1942,
|
|
165
|
-
"y": 788,
|
|
166
|
-
"timestamp": 2518,
|
|
167
|
-
"cursorType": "pointer",
|
|
168
|
-
"type": "move"
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
"x": 1943,
|
|
172
|
-
"y": 786,
|
|
173
|
-
"timestamp": 2560,
|
|
174
|
-
"cursorType": "pointer",
|
|
175
|
-
"type": "move"
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
"x": 1945,
|
|
179
|
-
"y": 784,
|
|
180
|
-
"timestamp": 2707,
|
|
181
|
-
"cursorType": "pointer",
|
|
182
|
-
"type": "move"
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
"x": 1945,
|
|
186
|
-
"y": 796,
|
|
187
|
-
"timestamp": 3544,
|
|
188
|
-
"cursorType": "pointer",
|
|
189
|
-
"type": "move"
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
"x": 1945,
|
|
193
|
-
"y": 817,
|
|
194
|
-
"timestamp": 3568,
|
|
195
|
-
"cursorType": "default",
|
|
196
|
-
"type": "move"
|
|
197
|
-
},
|
|
198
|
-
{
|
|
199
|
-
"x": 1951,
|
|
200
|
-
"y": 863,
|
|
201
|
-
"timestamp": 3589,
|
|
202
|
-
"cursorType": "default",
|
|
203
|
-
"type": "move"
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
"x": 1956,
|
|
207
|
-
"y": 925,
|
|
208
|
-
"timestamp": 3609,
|
|
209
|
-
"cursorType": "default",
|
|
210
|
-
"type": "move"
|
|
211
|
-
},
|
|
212
|
-
{
|
|
213
|
-
"x": 1966,
|
|
214
|
-
"y": 983,
|
|
215
|
-
"timestamp": 3630,
|
|
216
|
-
"cursorType": "default",
|
|
217
|
-
"type": "move"
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
"x": 1970,
|
|
221
|
-
"y": 1006,
|
|
222
|
-
"timestamp": 3650,
|
|
223
|
-
"cursorType": "text",
|
|
224
|
-
"type": "move"
|
|
225
|
-
},
|
|
226
|
-
{
|
|
227
|
-
"x": 1978,
|
|
228
|
-
"y": 1042,
|
|
229
|
-
"timestamp": 3675,
|
|
230
|
-
"cursorType": "default",
|
|
231
|
-
"type": "move"
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
"x": 1983,
|
|
235
|
-
"y": 1061,
|
|
236
|
-
"timestamp": 3693,
|
|
237
|
-
"cursorType": "default",
|
|
238
|
-
"type": "move"
|
|
239
|
-
},
|
|
240
|
-
{
|
|
241
|
-
"x": 1986,
|
|
242
|
-
"y": 1072,
|
|
243
|
-
"timestamp": 3713,
|
|
244
|
-
"cursorType": "text",
|
|
245
|
-
"type": "move"
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
"x": 1990,
|
|
249
|
-
"y": 1082,
|
|
250
|
-
"timestamp": 3734,
|
|
251
|
-
"cursorType": "text",
|
|
252
|
-
"type": "move"
|
|
253
|
-
},
|
|
254
|
-
{
|
|
255
|
-
"x": 1991,
|
|
256
|
-
"y": 1086,
|
|
257
|
-
"timestamp": 3755,
|
|
258
|
-
"cursorType": "text",
|
|
259
|
-
"type": "move"
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
"x": 1993,
|
|
263
|
-
"y": 1091,
|
|
264
|
-
"timestamp": 3776,
|
|
265
|
-
"cursorType": "text",
|
|
266
|
-
"type": "move"
|
|
267
|
-
},
|
|
268
|
-
{
|
|
269
|
-
"x": 1994,
|
|
270
|
-
"y": 1096,
|
|
271
|
-
"timestamp": 3797,
|
|
272
|
-
"cursorType": "text",
|
|
273
|
-
"type": "move"
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
"x": 1995,
|
|
277
|
-
"y": 1099,
|
|
278
|
-
"timestamp": 3818,
|
|
279
|
-
"cursorType": "text",
|
|
280
|
-
"type": "move"
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
"x": 1997,
|
|
284
|
-
"y": 1106,
|
|
285
|
-
"timestamp": 3841,
|
|
286
|
-
"cursorType": "text",
|
|
287
|
-
"type": "move"
|
|
288
|
-
},
|
|
289
|
-
{
|
|
290
|
-
"x": 1997,
|
|
291
|
-
"y": 1109,
|
|
292
|
-
"timestamp": 3859,
|
|
293
|
-
"cursorType": "text",
|
|
294
|
-
"type": "move"
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
"x": 1998,
|
|
298
|
-
"y": 1116,
|
|
299
|
-
"timestamp": 3882,
|
|
300
|
-
"cursorType": "text",
|
|
301
|
-
"type": "move"
|
|
302
|
-
},
|
|
303
|
-
{
|
|
304
|
-
"x": 2000,
|
|
305
|
-
"y": 1120,
|
|
306
|
-
"timestamp": 3902,
|
|
307
|
-
"cursorType": "text",
|
|
308
|
-
"type": "move"
|
|
309
|
-
},
|
|
310
|
-
{
|
|
311
|
-
"x": 2000,
|
|
312
|
-
"y": 1123,
|
|
313
|
-
"timestamp": 3924,
|
|
314
|
-
"cursorType": "text",
|
|
315
|
-
"type": "move"
|
|
316
|
-
},
|
|
317
|
-
{
|
|
318
|
-
"x": 2001,
|
|
319
|
-
"y": 1126,
|
|
320
|
-
"timestamp": 3945,
|
|
321
|
-
"cursorType": "text",
|
|
322
|
-
"type": "move"
|
|
323
|
-
},
|
|
324
|
-
{
|
|
325
|
-
"x": 2001,
|
|
326
|
-
"y": 1129,
|
|
327
|
-
"timestamp": 3967,
|
|
328
|
-
"cursorType": "text",
|
|
329
|
-
"type": "move"
|
|
330
|
-
},
|
|
331
|
-
{
|
|
332
|
-
"x": 2002,
|
|
333
|
-
"y": 1135,
|
|
334
|
-
"timestamp": 3986,
|
|
335
|
-
"cursorType": "pointer",
|
|
336
|
-
"type": "move"
|
|
337
|
-
},
|
|
338
|
-
{
|
|
339
|
-
"x": 2002,
|
|
340
|
-
"y": 1142,
|
|
341
|
-
"timestamp": 4007,
|
|
342
|
-
"cursorType": "pointer",
|
|
343
|
-
"type": "move"
|
|
344
|
-
},
|
|
345
|
-
{
|
|
346
|
-
"x": 2002,
|
|
347
|
-
"y": 1146,
|
|
348
|
-
"timestamp": 4027,
|
|
349
|
-
"cursorType": "pointer",
|
|
350
|
-
"type": "move"
|
|
351
|
-
},
|
|
352
|
-
{
|
|
353
|
-
"x": 2002,
|
|
354
|
-
"y": 1151,
|
|
355
|
-
"timestamp": 4049,
|
|
356
|
-
"cursorType": "pointer",
|
|
357
|
-
"type": "move"
|
|
358
|
-
}
|
|
359
|
-
]
|