node-mac-recorder 2.17.19 ā 2.17.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.
- package/.claude/settings.local.json +3 -1
- package/index.js +21 -200
- package/package.json +1 -1
- package/publish.sh +18 -0
- package/src/cursor_tracker.mm +37 -20
- package/cursor-data-1751364226346.json +0 -1
- package/cursor-data-1751364314136.json +0 -1
- package/cursor-data.json +0 -1
- package/cursor-debug-test.js +0 -60
- package/cursor-dpr-test.js +0 -73
- package/cursor-dpr-test.json +0 -1
- package/cursor-macbook-test.js +0 -63
- package/cursor-permission-test.js +0 -46
- package/cursor-scaling-debug.js +0 -53
- package/cursor-simple-test.js +0 -26
- package/debug-audio.js +0 -79
- package/debug-coordinates.js +0 -69
- package/debug-cursor-output.json +0 -1
- package/debug-macos14.js +0 -110
- package/debug-primary-window.js +0 -84
- package/debug-screen-selection.js +0 -81
- package/debug-window-selector.js +0 -178
- package/examples/electron-integration-example.js +0 -230
- package/examples/electron-preload.js +0 -46
- package/examples/electron-renderer.html +0 -634
- package/examples/integration-example.js +0 -228
- package/examples/window-selector-example.js +0 -254
- package/quick-cursor-test.json +0 -1
- package/test-both-cursor.json +0 -1
- package/test-cursor-fix.js +0 -105
- package/test-cursor-types.js +0 -117
- package/test-display-coordinates.js +0 -72
- package/test-integrated-recording.js +0 -120
- package/test-menubar-offset.js +0 -110
- package/test-output/primary-fix-test-1758266910543.json +0 -1
- package/test-output/unified-cursor-1758313640878.json +0 -1
- package/test-output/unified-cursor-1758313689471.json +0 -1
- package/test-primary-cursor.js +0 -154
- package/test-primary-fix.js +0 -120
- package/test-unified-cursor.js +0 -75
- package/test-window-recording.js +0 -149
package/index.js
CHANGED
|
@@ -456,9 +456,11 @@ class MacRecorder extends EventEmitter {
|
|
|
456
456
|
|
|
457
457
|
// Stop cursor tracking automatically
|
|
458
458
|
if (this.cursorCaptureInterval) {
|
|
459
|
-
|
|
459
|
+
try {
|
|
460
|
+
this.stopCursorCapture();
|
|
461
|
+
} catch (cursorError) {
|
|
460
462
|
console.warn('Cursor tracking failed to stop:', cursorError.message);
|
|
461
|
-
}
|
|
463
|
+
}
|
|
462
464
|
}
|
|
463
465
|
|
|
464
466
|
// Timer durdur
|
|
@@ -645,11 +647,9 @@ class MacRecorder extends EventEmitter {
|
|
|
645
647
|
*/
|
|
646
648
|
async startCursorCapture(intervalOrFilepath = 100, options = {}) {
|
|
647
649
|
let filepath;
|
|
648
|
-
let interval = 20; // Default 50 FPS
|
|
649
650
|
|
|
650
651
|
// Parameter parsing: number = interval, string = filepath
|
|
651
652
|
if (typeof intervalOrFilepath === "number") {
|
|
652
|
-
interval = Math.max(10, intervalOrFilepath); // Min 10ms
|
|
653
653
|
filepath = `cursor-data-${Date.now()}.json`;
|
|
654
654
|
} else if (typeof intervalOrFilepath === "string") {
|
|
655
655
|
filepath = intervalOrFilepath;
|
|
@@ -663,207 +663,28 @@ class MacRecorder extends EventEmitter {
|
|
|
663
663
|
throw new Error("Cursor capture is already running");
|
|
664
664
|
}
|
|
665
665
|
|
|
666
|
-
// Koordinat sistemi belirle: window-relative, display-relative veya global
|
|
667
|
-
if (options.windowRelative && options.windowInfo) {
|
|
668
|
-
const windowInfo = options.windowInfo;
|
|
669
|
-
const targetDisplay = windowInfo.targetDisplay || this.recordingDisplayInfo || null;
|
|
670
|
-
const captureArea = windowInfo.captureArea || null;
|
|
671
|
-
const hasNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
672
|
-
|
|
673
|
-
let globalX = hasNumber(windowInfo.x) ? windowInfo.x : null;
|
|
674
|
-
let globalY = hasNumber(windowInfo.y) ? windowInfo.y : null;
|
|
675
|
-
|
|
676
|
-
if (captureArea && targetDisplay) {
|
|
677
|
-
if (!hasNumber(globalX) && hasNumber(captureArea.x) && hasNumber(targetDisplay.x)) {
|
|
678
|
-
globalX = targetDisplay.x + captureArea.x;
|
|
679
|
-
}
|
|
680
|
-
if (!hasNumber(globalY) && hasNumber(captureArea.y) && hasNumber(targetDisplay.y)) {
|
|
681
|
-
globalY = targetDisplay.y + captureArea.y;
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
if (!hasNumber(globalX)) {
|
|
686
|
-
if (captureArea && hasNumber(captureArea.x) && targetDisplay && hasNumber(targetDisplay.x)) {
|
|
687
|
-
globalX = targetDisplay.x + captureArea.x;
|
|
688
|
-
} else {
|
|
689
|
-
globalX = hasNumber(captureArea?.x) ? captureArea.x : 0;
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
if (!hasNumber(globalY)) {
|
|
694
|
-
if (captureArea && hasNumber(captureArea.y) && targetDisplay && hasNumber(targetDisplay.y)) {
|
|
695
|
-
globalY = targetDisplay.y + captureArea.y;
|
|
696
|
-
} else {
|
|
697
|
-
globalY = hasNumber(captureArea?.y) ? captureArea.y : 0;
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
const displayOffsetX = captureArea && hasNumber(captureArea.x)
|
|
702
|
-
? captureArea.x
|
|
703
|
-
: (targetDisplay && hasNumber(globalX) && hasNumber(targetDisplay.x)
|
|
704
|
-
? globalX - targetDisplay.x
|
|
705
|
-
: globalX);
|
|
706
|
-
const displayOffsetY = captureArea && hasNumber(captureArea.y)
|
|
707
|
-
? captureArea.y
|
|
708
|
-
: (targetDisplay && hasNumber(globalY) && hasNumber(targetDisplay.y)
|
|
709
|
-
? globalY - targetDisplay.y
|
|
710
|
-
: globalY);
|
|
711
|
-
|
|
712
|
-
this.cursorDisplayInfo = {
|
|
713
|
-
displayId:
|
|
714
|
-
windowInfo.displayId ??
|
|
715
|
-
targetDisplay?.displayId ??
|
|
716
|
-
targetDisplay?.id ??
|
|
717
|
-
null,
|
|
718
|
-
x: globalX,
|
|
719
|
-
y: globalY,
|
|
720
|
-
width: windowInfo.width,
|
|
721
|
-
height: windowInfo.height,
|
|
722
|
-
windowRelative: true,
|
|
723
|
-
windowInfo: {
|
|
724
|
-
...windowInfo,
|
|
725
|
-
globalX,
|
|
726
|
-
globalY,
|
|
727
|
-
displayOffsetX,
|
|
728
|
-
displayOffsetY
|
|
729
|
-
},
|
|
730
|
-
targetDisplay,
|
|
731
|
-
captureArea
|
|
732
|
-
};
|
|
733
|
-
} else if (options.displayRelative && options.displayInfo) {
|
|
734
|
-
// Display recording: Use display-relative coordinates
|
|
735
|
-
this.cursorDisplayInfo = {
|
|
736
|
-
displayId: options.displayInfo.displayId,
|
|
737
|
-
x: options.displayInfo.x,
|
|
738
|
-
y: options.displayInfo.y,
|
|
739
|
-
width: options.displayInfo.width,
|
|
740
|
-
height: options.displayInfo.height,
|
|
741
|
-
displayRelative: true
|
|
742
|
-
};
|
|
743
|
-
} else if (this.recordingDisplayInfo) {
|
|
744
|
-
// Fallback: Use recording display info if available
|
|
745
|
-
this.cursorDisplayInfo = this.recordingDisplayInfo;
|
|
746
|
-
} else {
|
|
747
|
-
// Final fallback: Main display global coordinates
|
|
748
|
-
try {
|
|
749
|
-
const displays = await this.getDisplays();
|
|
750
|
-
const mainDisplay = displays.find((d) => d.isPrimary) || displays[0];
|
|
751
|
-
if (mainDisplay) {
|
|
752
|
-
this.cursorDisplayInfo = {
|
|
753
|
-
displayId: mainDisplay.id,
|
|
754
|
-
x: mainDisplay.x,
|
|
755
|
-
y: mainDisplay.y,
|
|
756
|
-
width: parseInt(mainDisplay.resolution.split("x")[0]),
|
|
757
|
-
height: parseInt(mainDisplay.resolution.split("x")[1]),
|
|
758
|
-
};
|
|
759
|
-
}
|
|
760
|
-
} catch (error) {
|
|
761
|
-
console.warn("Main display bilgisi alınamadı:", error.message);
|
|
762
|
-
this.cursorDisplayInfo = null; // Fallback: global koordinatlar
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
|
|
766
666
|
return new Promise((resolve, reject) => {
|
|
767
667
|
try {
|
|
768
|
-
//
|
|
769
|
-
const
|
|
770
|
-
fs.writeFileSync(filepath, "[");
|
|
771
|
-
|
|
772
|
-
this.cursorCaptureFile = filepath;
|
|
773
|
-
this.cursorCaptureStartTime = Date.now();
|
|
774
|
-
this.cursorCaptureFirstWrite = true;
|
|
775
|
-
this.lastCapturedData = null;
|
|
776
|
-
|
|
777
|
-
// JavaScript interval ile polling yap (daha sık - mouse event'leri yakalamak iƧin)
|
|
778
|
-
this.cursorCaptureInterval = setInterval(() => {
|
|
779
|
-
try {
|
|
780
|
-
const position = nativeBinding.getCursorPosition();
|
|
781
|
-
const timestamp = Date.now() - this.cursorCaptureStartTime;
|
|
782
|
-
|
|
783
|
-
// Transform coordinates based on recording type
|
|
784
|
-
let x = position.x;
|
|
785
|
-
let y = position.y;
|
|
786
|
-
let coordinateSystem = "global";
|
|
787
|
-
|
|
788
|
-
if (this.cursorDisplayInfo) {
|
|
789
|
-
if (this.cursorDisplayInfo.windowRelative) {
|
|
790
|
-
// Window recording: Use direct global-to-window transformation
|
|
791
|
-
// This works correctly for both primary and secondary displays
|
|
792
|
-
x = position.x - this.cursorDisplayInfo.x;
|
|
793
|
-
y = position.y - this.cursorDisplayInfo.y;
|
|
794
|
-
|
|
795
|
-
coordinateSystem = "window-relative";
|
|
796
|
-
|
|
797
|
-
// Window bounds check - skip if cursor is outside window
|
|
798
|
-
if (x < 0 || y < 0 || x >= this.cursorDisplayInfo.width || y >= this.cursorDisplayInfo.height) {
|
|
799
|
-
return; // Skip frame - cursor outside window
|
|
800
|
-
}
|
|
801
|
-
} else if (this.cursorDisplayInfo.displayRelative) {
|
|
802
|
-
// Display recording: Transform global ā display-relative coordinates
|
|
803
|
-
x = position.x - this.cursorDisplayInfo.x;
|
|
804
|
-
y = position.y - this.cursorDisplayInfo.y;
|
|
805
|
-
coordinateSystem = "display-relative";
|
|
806
|
-
|
|
807
|
-
// Display bounds check - skip if cursor is outside display
|
|
808
|
-
if (x < 0 || y < 0 || x >= this.cursorDisplayInfo.width || y >= this.cursorDisplayInfo.height) {
|
|
809
|
-
return; // Skip frame - cursor outside display
|
|
810
|
-
}
|
|
811
|
-
} else {
|
|
812
|
-
// Legacy fallback: Use global coordinates with basic offset
|
|
813
|
-
x = position.x - this.cursorDisplayInfo.x;
|
|
814
|
-
y = position.y - this.cursorDisplayInfo.y;
|
|
815
|
-
coordinateSystem = "display-relative";
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
const cursorData = {
|
|
820
|
-
x: x,
|
|
821
|
-
y: y,
|
|
822
|
-
timestamp: timestamp,
|
|
823
|
-
unixTimeMs: Date.now(),
|
|
824
|
-
cursorType: position.cursorType,
|
|
825
|
-
type: position.eventType || "move",
|
|
826
|
-
coordinateSystem: coordinateSystem,
|
|
827
|
-
// Include recording context for window-relative coordinates
|
|
828
|
-
...(this.cursorDisplayInfo?.windowRelative && {
|
|
829
|
-
windowInfo: {
|
|
830
|
-
width: this.cursorDisplayInfo.width,
|
|
831
|
-
height: this.cursorDisplayInfo.height,
|
|
832
|
-
displayId: this.cursorDisplayInfo.displayId
|
|
833
|
-
}
|
|
834
|
-
}),
|
|
835
|
-
// Include display context for display-relative coordinates
|
|
836
|
-
...(this.cursorDisplayInfo?.displayRelative && {
|
|
837
|
-
displayInfo: {
|
|
838
|
-
displayId: this.cursorDisplayInfo.displayId,
|
|
839
|
-
width: this.cursorDisplayInfo.width,
|
|
840
|
-
height: this.cursorDisplayInfo.height
|
|
841
|
-
}
|
|
842
|
-
})
|
|
843
|
-
};
|
|
844
|
-
|
|
845
|
-
// Sadece eventType deÄiÅtiÄinde veya pozisyon deÄiÅtiÄinde kaydet
|
|
846
|
-
if (this.shouldCaptureEvent(cursorData)) {
|
|
847
|
-
// Dosyaya ekle
|
|
848
|
-
const jsonString = JSON.stringify(cursorData);
|
|
668
|
+
// Native cursor tracking kullan - hem screen hem window iƧin aynı yƶntem
|
|
669
|
+
const success = nativeBinding.startCursorTracking(filepath);
|
|
849
670
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
fs.appendFileSync(filepath, "," + jsonString);
|
|
855
|
-
}
|
|
671
|
+
if (success) {
|
|
672
|
+
this.cursorCaptureFile = filepath;
|
|
673
|
+
this.cursorCaptureStartTime = Date.now();
|
|
674
|
+
this.cursorCaptureInterval = true; // Mark as active
|
|
856
675
|
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
}
|
|
861
|
-
console.error("Cursor capture error:", error);
|
|
862
|
-
}
|
|
863
|
-
}, interval); // Configurable FPS
|
|
676
|
+
this.emit("cursorCaptureStarted", {
|
|
677
|
+
filepath: filepath,
|
|
678
|
+
timestamp: Date.now()
|
|
679
|
+
});
|
|
864
680
|
|
|
865
|
-
|
|
866
|
-
|
|
681
|
+
resolve({
|
|
682
|
+
filepath: filepath,
|
|
683
|
+
started: true
|
|
684
|
+
});
|
|
685
|
+
} else {
|
|
686
|
+
reject(new Error("Failed to start native cursor tracking"));
|
|
687
|
+
}
|
|
867
688
|
} catch (error) {
|
|
868
689
|
reject(error);
|
|
869
690
|
}
|
package/package.json
CHANGED
package/publish.sh
CHANGED
|
@@ -26,6 +26,24 @@ if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
|
|
26
26
|
exit 1
|
|
27
27
|
fi
|
|
28
28
|
|
|
29
|
+
# Clean up test files and video files before publishing
|
|
30
|
+
echo "š§¹ Cleaning up test files and video files..."
|
|
31
|
+
|
|
32
|
+
# Remove video files (MP4, MOV, AVI, etc.)
|
|
33
|
+
find . -maxdepth 1 -type f \( -name "*.mp4" -o -name "*.mov" -o -name "*.avi" -o -name "*.mkv" -o -name "*.webm" \) -delete
|
|
34
|
+
|
|
35
|
+
# Remove test output directories
|
|
36
|
+
rm -rf test-output debug-output
|
|
37
|
+
|
|
38
|
+
# Remove test files and temporary files
|
|
39
|
+
find . -maxdepth 1 -type f \( -name "*test*.json" -o -name "*debug*.json" -o -name "*cursor*.json" -o -name "temp-*" -o -name "*-temp.*" -o -name "*.tmp" \) -delete
|
|
40
|
+
|
|
41
|
+
# Remove test JavaScript files that shouldn't be published
|
|
42
|
+
find . -maxdepth 1 -type f -name "*test*.js" ! -name "test.js" -delete
|
|
43
|
+
find . -maxdepth 1 -type f -name "*debug*.js" -delete
|
|
44
|
+
|
|
45
|
+
echo "ā
Cleanup completed"
|
|
46
|
+
|
|
29
47
|
# Check if there are uncommitted changes
|
|
30
48
|
if ! git diff --quiet || ! git diff --cached --quiet; then
|
|
31
49
|
echo "š Adding all changes to git..."
|
package/src/cursor_tracker.mm
CHANGED
|
@@ -13,7 +13,7 @@ static CFMachPortRef g_eventTap = NULL;
|
|
|
13
13
|
static CFRunLoopSourceRef g_runLoopSource = NULL;
|
|
14
14
|
static NSDate *g_trackingStartTime = nil;
|
|
15
15
|
static NSString *g_outputPath = nil;
|
|
16
|
-
static
|
|
16
|
+
static dispatch_source_t g_cursorTimer = nil;
|
|
17
17
|
static int g_debugCallbackCount = 0;
|
|
18
18
|
static NSFileHandle *g_fileHandle = nil;
|
|
19
19
|
static bool g_isFirstWrite = true;
|
|
@@ -623,8 +623,16 @@ CGEventRef eventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef eve
|
|
|
623
623
|
void cursorTimerCallback() {
|
|
624
624
|
@autoreleasepool {
|
|
625
625
|
g_debugCallbackCount++; // Timer callback ƧaÄrıldıÄını say
|
|
626
|
-
|
|
626
|
+
|
|
627
|
+
static int callCount = 0;
|
|
628
|
+
callCount++;
|
|
629
|
+
if (callCount <= 3) {
|
|
630
|
+
NSLog(@"š Timer callback #%d called", callCount);
|
|
631
|
+
}
|
|
632
|
+
|
|
627
633
|
if (!g_isCursorTracking || !g_trackingStartTime || !g_fileHandle) {
|
|
634
|
+
NSLog(@"ā Timer callback stopped - tracking:%d, startTime:%@, fileHandle:%@",
|
|
635
|
+
g_isCursorTracking, g_trackingStartTime ? @"OK" : @"nil", g_fileHandle ? @"OK" : @"nil");
|
|
628
636
|
return;
|
|
629
637
|
}
|
|
630
638
|
|
|
@@ -673,16 +681,14 @@ void cursorTimerCallback() {
|
|
|
673
681
|
void cleanupCursorTracking() {
|
|
674
682
|
g_isCursorTracking = false;
|
|
675
683
|
|
|
676
|
-
// Timer temizle
|
|
684
|
+
// GCD Timer temizle
|
|
677
685
|
if (g_cursorTimer) {
|
|
678
|
-
|
|
686
|
+
dispatch_source_cancel(g_cursorTimer);
|
|
687
|
+
dispatch_release(g_cursorTimer);
|
|
679
688
|
g_cursorTimer = nil;
|
|
680
689
|
}
|
|
681
690
|
|
|
682
|
-
|
|
683
|
-
[g_timerTarget autorelease];
|
|
684
|
-
g_timerTarget = nil;
|
|
685
|
-
}
|
|
691
|
+
// Timer target artık kullanılmıyor (GCD kullanıyoruz)
|
|
686
692
|
|
|
687
693
|
// Dosyayı ƶnce kapat (en ƶnemli iÅlem)
|
|
688
694
|
if (g_fileHandle) {
|
|
@@ -788,19 +794,30 @@ Napi::Value StartCursorTracking(const Napi::CallbackInfo& info) {
|
|
|
788
794
|
CGEventTapEnable(g_eventTap, true);
|
|
789
795
|
}
|
|
790
796
|
|
|
791
|
-
//
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
797
|
+
// GCD Timer kullan (Node.js ile uyumlu)
|
|
798
|
+
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
|
799
|
+
g_cursorTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
|
|
800
|
+
|
|
801
|
+
if (g_cursorTimer) {
|
|
802
|
+
dispatch_source_set_timer(g_cursorTimer,
|
|
803
|
+
dispatch_time(DISPATCH_TIME_NOW, 50 * NSEC_PER_MSEC), // Start after 50ms
|
|
804
|
+
50 * NSEC_PER_MSEC, // Repeat every 50ms (20 FPS)
|
|
805
|
+
10 * NSEC_PER_MSEC); // Leeway of 10ms
|
|
806
|
+
|
|
807
|
+
dispatch_source_set_event_handler(g_cursorTimer, ^{
|
|
808
|
+
cursorTimerCallback();
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
dispatch_resume(g_cursorTimer);
|
|
812
|
+
}
|
|
813
|
+
|
|
803
814
|
g_isCursorTracking = true;
|
|
815
|
+
|
|
816
|
+
NSLog(@"šÆ Native cursor tracking started with timer and event tap");
|
|
817
|
+
NSLog(@"šÆ File handle: %@", g_fileHandle ? @"OK" : @"FAILED");
|
|
818
|
+
NSLog(@"šÆ Timer: %@", g_cursorTimer ? @"OK" : @"FAILED");
|
|
819
|
+
NSLog(@"šÆ Event tap: %@", g_eventTap ? @"OK" : @"FAILED");
|
|
820
|
+
|
|
804
821
|
return Napi::Boolean::New(env, true);
|
|
805
822
|
|
|
806
823
|
} @catch (NSException *exception) {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
[]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
[]
|
package/cursor-data.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
[{"x":1151,"y":726,"timestamp":20,"cursorType":"text","type":"move"}
|
package/cursor-debug-test.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
const MacRecorder = require('./index.js');
|
|
2
|
-
|
|
3
|
-
console.log('š Debugging cursor coordinate scaling issue...\n');
|
|
4
|
-
|
|
5
|
-
const recorder = new MacRecorder();
|
|
6
|
-
|
|
7
|
-
async function testCursorScaling() {
|
|
8
|
-
console.log('Getting display info...');
|
|
9
|
-
const displays = await recorder.getDisplays();
|
|
10
|
-
|
|
11
|
-
displays.forEach((display, index) => {
|
|
12
|
-
console.log(`Display ${index}:`);
|
|
13
|
-
console.log(` Resolution: ${display.resolution}`);
|
|
14
|
-
console.log(` Position: (${display.x}, ${display.y})`);
|
|
15
|
-
console.log(` Primary: ${display.isPrimary}`);
|
|
16
|
-
console.log(` ID: ${display.id}`);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
console.log('\nšÆ Please move your mouse to different corners and press Enter...');
|
|
20
|
-
console.log('This will help us understand the coordinate mapping issue.\n');
|
|
21
|
-
|
|
22
|
-
const readline = require('readline');
|
|
23
|
-
const rl = readline.createInterface({
|
|
24
|
-
input: process.stdin,
|
|
25
|
-
output: process.stdout
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
let testCount = 0;
|
|
29
|
-
const testPositions = [
|
|
30
|
-
'Top-Left corner of the display',
|
|
31
|
-
'Top-Right corner of the display',
|
|
32
|
-
'Bottom-Left corner of the display',
|
|
33
|
-
'Bottom-Right corner of the display',
|
|
34
|
-
'Center of the display'
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
function nextTest() {
|
|
38
|
-
if (testCount >= testPositions.length) {
|
|
39
|
-
console.log('\nā
Test completed!');
|
|
40
|
-
rl.close();
|
|
41
|
-
process.exit(0);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
console.log(`\nš Test ${testCount + 1}: Move mouse to ${testPositions[testCount]} and press Enter:`);
|
|
46
|
-
rl.question('', () => {
|
|
47
|
-
const position = recorder.getCursorPosition();
|
|
48
|
-
console.log(` Raw cursor position: (${position.rawX || 'N/A'}, ${position.rawY || 'N/A'})`);
|
|
49
|
-
console.log(` Logical cursor position: (${position.x}, ${position.y})`);
|
|
50
|
-
console.log(` Scale factor: ${position.scaleFactor || 'N/A'}x`);
|
|
51
|
-
|
|
52
|
-
testCount++;
|
|
53
|
-
nextTest();
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
nextTest();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
testCursorScaling().catch(console.error);
|
package/cursor-dpr-test.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
const MacRecorder = require('./index.js');
|
|
2
|
-
|
|
3
|
-
console.log('š§Ŗ Testing cursor DPR scaling fixes...\n');
|
|
4
|
-
|
|
5
|
-
const recorder = new MacRecorder();
|
|
6
|
-
|
|
7
|
-
// Test basic cursor position
|
|
8
|
-
console.log('1. Testing basic cursor position:');
|
|
9
|
-
try {
|
|
10
|
-
const position = recorder.getCursorPosition();
|
|
11
|
-
console.log(` Position: (${position.x}, ${position.y})`);
|
|
12
|
-
|
|
13
|
-
// If we have scaling debug info, show it
|
|
14
|
-
if (position.scaleFactor) {
|
|
15
|
-
console.log(` Scale factor: ${position.scaleFactor}x`);
|
|
16
|
-
console.log(` Raw position: (${position.rawX}, ${position.rawY})`);
|
|
17
|
-
console.log(` Logical position: (${position.x}, ${position.y})`);
|
|
18
|
-
}
|
|
19
|
-
} catch (error) {
|
|
20
|
-
console.error(' Error:', error.message);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
console.log('\n2. Testing display information:');
|
|
24
|
-
recorder.getDisplays().then(displays => {
|
|
25
|
-
displays.forEach((display, index) => {
|
|
26
|
-
console.log(` Display ${index}: ${display.resolution} at (${display.x}, ${display.y})`);
|
|
27
|
-
console.log(` Primary: ${display.isPrimary}, ID: ${display.id}`);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
console.log('\n3. Testing cursor capture with DPR fix:');
|
|
31
|
-
const outputFile = 'cursor-dpr-test.json';
|
|
32
|
-
|
|
33
|
-
recorder.startCursorCapture(outputFile, 50).then(() => {
|
|
34
|
-
console.log(` ā
Cursor capture started, saving to ${outputFile}`);
|
|
35
|
-
console.log(' Move your mouse around for 5 seconds...');
|
|
36
|
-
|
|
37
|
-
setTimeout(() => {
|
|
38
|
-
recorder.stopCursorCapture().then(() => {
|
|
39
|
-
console.log(' ā
Cursor capture stopped');
|
|
40
|
-
|
|
41
|
-
// Read and analyze the captured data
|
|
42
|
-
const fs = require('fs');
|
|
43
|
-
try {
|
|
44
|
-
const data = JSON.parse(fs.readFileSync(outputFile, 'utf8'));
|
|
45
|
-
if (data.length > 0) {
|
|
46
|
-
const first = data[0];
|
|
47
|
-
const last = data[data.length - 1];
|
|
48
|
-
|
|
49
|
-
console.log(` š Captured ${data.length} cursor events`);
|
|
50
|
-
console.log(` š First: (${first.x}, ${first.y}) ${first.coordinateSystem || 'unknown'}`);
|
|
51
|
-
console.log(` š Last: (${last.x}, ${last.y}) ${last.coordinateSystem || 'unknown'}`);
|
|
52
|
-
|
|
53
|
-
// Check coordinate system
|
|
54
|
-
const hasCoordinateSystem = data.some(d => d.coordinateSystem);
|
|
55
|
-
console.log(` šÆ Coordinate system info: ${hasCoordinateSystem ? 'Present' : 'Missing'}`);
|
|
56
|
-
} else {
|
|
57
|
-
console.log(' ā ļø No cursor events captured');
|
|
58
|
-
}
|
|
59
|
-
} catch (readError) {
|
|
60
|
-
console.error(' ā Error reading capture file:', readError.message);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
process.exit(0);
|
|
64
|
-
});
|
|
65
|
-
}, 5000);
|
|
66
|
-
}).catch(error => {
|
|
67
|
-
console.error(' ā Cursor capture failed:', error.message);
|
|
68
|
-
process.exit(1);
|
|
69
|
-
});
|
|
70
|
-
}).catch(error => {
|
|
71
|
-
console.error(' Error getting displays:', error.message);
|
|
72
|
-
process.exit(1);
|
|
73
|
-
});
|
package/cursor-dpr-test.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
[]
|
package/cursor-macbook-test.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
const MacRecorder = require('./index.js');
|
|
2
|
-
|
|
3
|
-
async function testMacBookCursor() {
|
|
4
|
-
console.log('š„ļø Testing cursor on MacBook internal display...\n');
|
|
5
|
-
|
|
6
|
-
const recorder = new MacRecorder();
|
|
7
|
-
|
|
8
|
-
// Get displays
|
|
9
|
-
const displays = await recorder.getDisplays();
|
|
10
|
-
console.log('šŗ Available displays:');
|
|
11
|
-
displays.forEach((display, index) => {
|
|
12
|
-
console.log(` Display ${index}: ${display.resolution} at (${display.x}, ${display.y}) - Primary: ${display.isPrimary}`);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
console.log('\nšÆ Move your mouse to the PRIMARY MacBook display and press any key...');
|
|
16
|
-
console.log('(Make sure cursor is on the built-in MacBook screen, not external monitor)\n');
|
|
17
|
-
|
|
18
|
-
// Wait for keypress
|
|
19
|
-
await new Promise((resolve) => {
|
|
20
|
-
process.stdin.setRawMode(true);
|
|
21
|
-
process.stdin.resume();
|
|
22
|
-
process.stdin.once('data', () => {
|
|
23
|
-
process.stdin.setRawMode(false);
|
|
24
|
-
resolve();
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
console.log('š Testing cursor position on MacBook display:');
|
|
29
|
-
for (let i = 0; i < 3; i++) {
|
|
30
|
-
const position = recorder.getCursorPosition();
|
|
31
|
-
console.log(`\n Test ${i+1}:`);
|
|
32
|
-
console.log(` Cursor: (${position.x}, ${position.y})`);
|
|
33
|
-
console.log(` Cursor type: ${position.cursorType}`);
|
|
34
|
-
|
|
35
|
-
// Check which display cursor is on
|
|
36
|
-
const primaryDisplay = displays.find(d => d.isPrimary);
|
|
37
|
-
if (primaryDisplay) {
|
|
38
|
-
const isOnPrimary = position.x >= primaryDisplay.x &&
|
|
39
|
-
position.x < primaryDisplay.x + parseInt(primaryDisplay.resolution.split('x')[0]) &&
|
|
40
|
-
position.y >= primaryDisplay.y &&
|
|
41
|
-
position.y < primaryDisplay.y + parseInt(primaryDisplay.resolution.split('x')[1]);
|
|
42
|
-
|
|
43
|
-
console.log(` On primary display: ${isOnPrimary ? 'ā
YES' : 'ā NO'}`);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (position.scaleFactor) {
|
|
47
|
-
console.log(` Scale factor: ${position.scaleFactor}x`);
|
|
48
|
-
if (position.displayInfo) {
|
|
49
|
-
console.log(` Display logical: ${position.displayInfo.logicalWidth}x${position.displayInfo.logicalHeight}`);
|
|
50
|
-
console.log(` Display physical: ${position.displayInfo.physicalWidth}x${position.displayInfo.physicalHeight}`);
|
|
51
|
-
console.log(` Raw cursor: (${position.rawX}, ${position.rawY})`);
|
|
52
|
-
}
|
|
53
|
-
} else {
|
|
54
|
-
console.log(` ā ļø No scaling info detected`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
process.exit(0);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
testMacBookCursor().catch(console.error);
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
const MacRecorder = require('./index.js');
|
|
2
|
-
|
|
3
|
-
async function testCursorPermissions() {
|
|
4
|
-
console.log('š Testing cursor tracking permissions...\n');
|
|
5
|
-
|
|
6
|
-
const recorder = new MacRecorder();
|
|
7
|
-
|
|
8
|
-
// Check permissions first
|
|
9
|
-
console.log('1. Checking permissions:');
|
|
10
|
-
const permissions = await recorder.checkPermissions();
|
|
11
|
-
console.log(' Screen Recording:', permissions.screenRecording ? 'ā
' : 'ā');
|
|
12
|
-
console.log(' Accessibility:', permissions.accessibility ? 'ā
' : 'ā');
|
|
13
|
-
console.log(' Microphone:', permissions.microphone ? 'ā
' : 'ā');
|
|
14
|
-
|
|
15
|
-
if (permissions.error) {
|
|
16
|
-
console.log(' Error:', permissions.error);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
console.log('\n2. Testing direct cursor position (no capture):');
|
|
20
|
-
for (let i = 0; i < 5; i++) {
|
|
21
|
-
try {
|
|
22
|
-
const position = recorder.getCursorPosition();
|
|
23
|
-
console.log(` Position ${i+1}: (${position.x}, ${position.y}) - ${position.cursorType}`);
|
|
24
|
-
|
|
25
|
-
if (position.scaleFactor) {
|
|
26
|
-
console.log(` Scale: ${position.scaleFactor}x, Display: (${position.displayInfo?.displayX}, ${position.displayInfo?.displayY})`);
|
|
27
|
-
console.log(` Logical: ${position.displayInfo?.logicalWidth}x${position.displayInfo?.logicalHeight}`);
|
|
28
|
-
console.log(` Physical: ${position.displayInfo?.physicalWidth}x${position.displayInfo?.physicalHeight}`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
32
|
-
} catch (error) {
|
|
33
|
-
console.error(` Error getting position ${i+1}:`, error.message);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
console.log('\n3. Testing cursor capture status:');
|
|
38
|
-
const status = recorder.getCursorCaptureStatus();
|
|
39
|
-
console.log(' Is Capturing:', status.isCapturing);
|
|
40
|
-
console.log(' Output File:', status.outputFile);
|
|
41
|
-
console.log(' Display Info:', status.displayInfo);
|
|
42
|
-
|
|
43
|
-
process.exit(0);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
testCursorPermissions().catch(console.error);
|