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.
Files changed (41) hide show
  1. package/.claude/settings.local.json +3 -1
  2. package/index.js +21 -200
  3. package/package.json +1 -1
  4. package/publish.sh +18 -0
  5. package/src/cursor_tracker.mm +37 -20
  6. package/cursor-data-1751364226346.json +0 -1
  7. package/cursor-data-1751364314136.json +0 -1
  8. package/cursor-data.json +0 -1
  9. package/cursor-debug-test.js +0 -60
  10. package/cursor-dpr-test.js +0 -73
  11. package/cursor-dpr-test.json +0 -1
  12. package/cursor-macbook-test.js +0 -63
  13. package/cursor-permission-test.js +0 -46
  14. package/cursor-scaling-debug.js +0 -53
  15. package/cursor-simple-test.js +0 -26
  16. package/debug-audio.js +0 -79
  17. package/debug-coordinates.js +0 -69
  18. package/debug-cursor-output.json +0 -1
  19. package/debug-macos14.js +0 -110
  20. package/debug-primary-window.js +0 -84
  21. package/debug-screen-selection.js +0 -81
  22. package/debug-window-selector.js +0 -178
  23. package/examples/electron-integration-example.js +0 -230
  24. package/examples/electron-preload.js +0 -46
  25. package/examples/electron-renderer.html +0 -634
  26. package/examples/integration-example.js +0 -228
  27. package/examples/window-selector-example.js +0 -254
  28. package/quick-cursor-test.json +0 -1
  29. package/test-both-cursor.json +0 -1
  30. package/test-cursor-fix.js +0 -105
  31. package/test-cursor-types.js +0 -117
  32. package/test-display-coordinates.js +0 -72
  33. package/test-integrated-recording.js +0 -120
  34. package/test-menubar-offset.js +0 -110
  35. package/test-output/primary-fix-test-1758266910543.json +0 -1
  36. package/test-output/unified-cursor-1758313640878.json +0 -1
  37. package/test-output/unified-cursor-1758313689471.json +0 -1
  38. package/test-primary-cursor.js +0 -154
  39. package/test-primary-fix.js +0 -120
  40. package/test-unified-cursor.js +0 -75
  41. package/test-window-recording.js +0 -149
@@ -7,7 +7,9 @@
7
7
  "Bash(git checkout:*)",
8
8
  "WebSearch",
9
9
  "WebFetch(domain:stackoverflow.com)",
10
- "Bash(timeout:*)"
10
+ "Bash(timeout:*)",
11
+ "Bash(grep:*)",
12
+ "Bash(./test-cleanup.sh:*)"
11
13
  ],
12
14
  "deny": [],
13
15
  "ask": []
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
- this.stopCursorCapture().catch(cursorError => {
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
- // Dosyayı oluştur ve temizle
769
- const fs = require("fs");
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
- if (this.cursorCaptureFirstWrite) {
851
- fs.appendFileSync(filepath, jsonString);
852
- this.cursorCaptureFirstWrite = false;
853
- } else {
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
- // Son pozisyonu sakla
858
- this.lastCapturedData = { ...cursorData };
859
- }
860
- } catch (error) {
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
- this.emit("cursorCaptureStarted", filepath);
866
- resolve(true);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.17.19",
3
+ "version": "2.17.21",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
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..."
@@ -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 NSTimer *g_cursorTimer = nil;
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
- [g_cursorTimer invalidate];
686
+ dispatch_source_cancel(g_cursorTimer);
687
+ dispatch_release(g_cursorTimer);
679
688
  g_cursorTimer = nil;
680
689
  }
681
690
 
682
- if (g_timerTarget) {
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
- // NSTimer kullan (main thread'de çalışır)
792
- g_timerTarget = [[CursorTimerTarget alloc] init];
793
-
794
- g_cursorTimer = [NSTimer timerWithTimeInterval:0.05 // 50ms (20 FPS)
795
- target:g_timerTarget
796
- selector:@selector(timerCallback:)
797
- userInfo:nil
798
- repeats:YES];
799
-
800
- // Main run loop'a ekle
801
- [[NSRunLoop mainRunLoop] addTimer:g_cursorTimer forMode:NSRunLoopCommonModes];
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"}
@@ -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);
@@ -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
- });
@@ -1 +0,0 @@
1
- []
@@ -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);