node-mac-recorder 2.17.20 โ†’ 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.
@@ -1,105 +0,0 @@
1
- const MacRecorder = require('./index.js');
2
-
3
- async function testCursorCoordinates() {
4
- console.log('๐Ÿงช Testing cursor coordinate fixes for window recording...');
5
-
6
- const recorder = new MacRecorder();
7
-
8
- try {
9
- // Get available windows and displays
10
- const windows = await recorder.getWindows();
11
- const displays = await recorder.getDisplays();
12
-
13
- console.log('\n๐Ÿ“ฑ Available displays:');
14
- displays.forEach((display, i) => {
15
- console.log(` ${i + 1}. Display ${display.id}: ${display.resolution} at (${display.x}, ${display.y}) ${display.isPrimary ? '(Primary)' : ''}`);
16
- });
17
-
18
- console.log('\n๐ŸชŸ Available windows:');
19
- windows.slice(0, 5).forEach((window, i) => {
20
- console.log(` ${i + 1}. ${window.title} (${window.app}) - ${window.width}x${window.height} at (${window.x}, ${window.y})`);
21
- });
22
-
23
- if (windows.length === 0) {
24
- console.log('โŒ No windows available for testing');
25
- return;
26
- }
27
-
28
- // Pick the first available window for testing
29
- const testWindow = windows[0];
30
- console.log(`\n๐ŸŽฏ Testing with window: ${testWindow.title}`);
31
- console.log(` Window position: (${testWindow.x}, ${testWindow.y})`);
32
- console.log(` Window size: ${testWindow.width}x${testWindow.height}`);
33
-
34
- // Check current cursor position before recording
35
- const cursorPos = recorder.getCursorPosition();
36
- console.log(`\n๐Ÿ–ฑ๏ธ Current cursor position (global): (${cursorPos.x}, ${cursorPos.y})`);
37
-
38
- // Setup recording options for window recording
39
- recorder.options.windowId = testWindow.id;
40
- recorder.options.captureCursor = true;
41
-
42
- console.log('\n๐Ÿ”ง Starting cursor capture test for window recording...');
43
-
44
- // Start cursor capture with window-relative coordinates
45
- const outputFile = `./test-output/cursor-test-window-${Date.now()}.json`;
46
-
47
- // Start cursor tracking first to see if coordinate transformation works
48
- await recorder.startCursorCapture(outputFile, {
49
- windowRelative: true,
50
- windowInfo: {
51
- x: testWindow.x,
52
- y: testWindow.y,
53
- width: testWindow.width,
54
- height: testWindow.height,
55
- displayId: null // Let it auto-detect
56
- }
57
- });
58
-
59
- console.log('โœ… Cursor capture started successfully!');
60
- console.log('๐Ÿ–ฑ๏ธ Move your mouse around the window for 5 seconds...');
61
- console.log(` Window bounds: (0, 0) to (${testWindow.width}, ${testWindow.height})`);
62
-
63
- // Wait for 5 seconds to capture cursor movements
64
- await new Promise(resolve => setTimeout(resolve, 5000));
65
-
66
- console.log('\n๐Ÿ›‘ Stopping cursor capture...');
67
- await recorder.stopCursorCapture();
68
-
69
- console.log(`โœ… Test completed! Check cursor data in: ${outputFile}`);
70
-
71
- // Read and analyze some cursor data
72
- const fs = require('fs');
73
- if (fs.existsSync(outputFile)) {
74
- const cursorData = JSON.parse(fs.readFileSync(outputFile, 'utf8'));
75
- console.log(`\n๐Ÿ“Š Captured ${cursorData.length} cursor events`);
76
-
77
- if (cursorData.length > 0) {
78
- const first = cursorData[0];
79
- const last = cursorData[cursorData.length - 1];
80
-
81
- console.log(` First event: (${first.x}, ${first.y}) - ${first.coordinateSystem}`);
82
- console.log(` Last event: (${last.x}, ${last.y}) - ${last.coordinateSystem}`);
83
-
84
- // Check if coordinates are within window bounds
85
- const inBounds = cursorData.filter(event =>
86
- event.x >= 0 && event.x < testWindow.width &&
87
- event.y >= 0 && event.y < testWindow.height
88
- );
89
-
90
- console.log(` Events within window bounds: ${inBounds.length}/${cursorData.length} (${Math.round(inBounds.length/cursorData.length*100)}%)`);
91
-
92
- if (inBounds.length > 0) {
93
- console.log('โœ… Cursor coordinates appear to be correctly transformed to window-relative!');
94
- } else {
95
- console.log('โŒ No cursor coordinates are within window bounds - transformation may be incorrect');
96
- }
97
- }
98
- }
99
-
100
- } catch (error) {
101
- console.error('โŒ Test failed:', error.message);
102
- }
103
- }
104
-
105
- testCursorCoordinates().catch(console.error);
@@ -1,117 +0,0 @@
1
- const MacRecorder = require('./index.js');
2
-
3
- async function testCursorTypes() {
4
- console.log('๐Ÿงช Testing improved cursor type detection...');
5
-
6
- const recorder = new MacRecorder();
7
-
8
- try {
9
- // Test basic cursor position and type detection
10
- console.log('\n๐Ÿ“ Current cursor state:');
11
- const cursorPos = recorder.getCursorPosition();
12
- console.log(` Position: (${cursorPos.x}, ${cursorPos.y})`);
13
- console.log(` Type: ${cursorPos.cursorType}`);
14
- console.log(` Event: ${cursorPos.eventType}`);
15
-
16
- console.log('\n๐Ÿ–ฑ๏ธ Starting continuous cursor type monitoring...');
17
- console.log('๐Ÿ“‹ Instructions:');
18
- console.log(' 1. Move mouse over different UI elements');
19
- console.log(' 2. Hover over buttons, text fields, links, window borders');
20
- console.log(' 3. Try resize handles on windows');
21
- console.log(' 4. Move over different applications');
22
- console.log(' 5. Test will run for 15 seconds');
23
-
24
- const cursorData = [];
25
- let lastReportedType = null;
26
- let typeChangeCount = 0;
27
-
28
- const startTime = Date.now();
29
- const testDuration = 15000; // 15 seconds
30
-
31
- // Continuous monitoring
32
- const monitor = setInterval(() => {
33
- const pos = recorder.getCursorPosition();
34
- const currentType = pos.cursorType;
35
-
36
- // Record all data for analysis
37
- cursorData.push({
38
- timestamp: Date.now() - startTime,
39
- x: pos.x,
40
- y: pos.y,
41
- type: currentType,
42
- event: pos.eventType
43
- });
44
-
45
- // Report type changes immediately
46
- if (currentType !== lastReportedType) {
47
- const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
48
- console.log(` [${elapsed}s] Cursor changed: ${lastReportedType || 'unknown'} โ†’ ${currentType} at (${pos.x}, ${pos.y})`);
49
- lastReportedType = currentType;
50
- typeChangeCount++;
51
- }
52
- }, 50); // Check every 50ms for high responsiveness
53
-
54
- // Stop after test duration
55
- setTimeout(() => {
56
- clearInterval(monitor);
57
-
58
- console.log('\n๐Ÿ“Š Test Results:');
59
- console.log(` Total cursor events: ${cursorData.length}`);
60
- console.log(` Cursor type changes: ${typeChangeCount}`);
61
- console.log(` Test duration: ${testDuration/1000} seconds`);
62
-
63
- // Analyze cursor types detected
64
- const typeDistribution = {};
65
- cursorData.forEach(data => {
66
- typeDistribution[data.type] = (typeDistribution[data.type] || 0) + 1;
67
- });
68
-
69
- console.log('\n๐ŸŽฏ Cursor types detected:');
70
- Object.entries(typeDistribution)
71
- .sort(([,a], [,b]) => b - a)
72
- .forEach(([type, count]) => {
73
- const percentage = ((count / cursorData.length) * 100).toFixed(1);
74
- console.log(` ${type}: ${count} times (${percentage}%)`);
75
- });
76
-
77
- // Responsiveness analysis
78
- const typeChanges = cursorData.filter((data, i) =>
79
- i === 0 || data.type !== cursorData[i-1].type
80
- );
81
-
82
- if (typeChanges.length > 1) {
83
- console.log('\nโšก Responsiveness Analysis:');
84
- console.log(` First type change at: ${typeChanges[1].timestamp}ms`);
85
- console.log(` Last type change at: ${typeChanges[typeChanges.length-1].timestamp}ms`);
86
- console.log(` Average detection frequency: ${(cursorData.length / (testDuration/1000)).toFixed(1)} checks/sec`);
87
-
88
- if (typeChangeCount > 0) {
89
- console.log('โœ… Cursor type detection is working and responsive!');
90
- } else {
91
- console.log('โš ๏ธ No cursor type changes detected - try moving over different UI elements');
92
- }
93
- }
94
-
95
- // Save detailed log for analysis
96
- const fs = require('fs');
97
- const logFile = `./test-output/cursor-types-test-${Date.now()}.json`;
98
- fs.writeFileSync(logFile, JSON.stringify({
99
- summary: {
100
- totalEvents: cursorData.length,
101
- typeChanges: typeChangeCount,
102
- duration: testDuration,
103
- typeDistribution
104
- },
105
- events: cursorData
106
- }, null, 2));
107
-
108
- console.log(`\n๐Ÿ’พ Detailed log saved to: ${logFile}`);
109
-
110
- }, testDuration);
111
-
112
- } catch (error) {
113
- console.error('โŒ Test failed:', error.message);
114
- }
115
- }
116
-
117
- testCursorTypes().catch(console.error);
@@ -1,72 +0,0 @@
1
- const MacRecorder = require('./index.js');
2
-
3
- async function testDisplayCoordinates() {
4
- console.log('๐Ÿงช Testing cursor coordinate behavior across displays...');
5
-
6
- const recorder = new MacRecorder();
7
-
8
- try {
9
- const displays = await recorder.getDisplays();
10
-
11
- console.log('\n๐Ÿ“ฑ Display information:');
12
- displays.forEach((display, i) => {
13
- const type = display.isPrimary ? 'PRIMARY' : 'SECONDARY';
14
- console.log(` ${type} Display ${display.id}: ${display.resolution} at (${display.x}, ${display.y})`);
15
- });
16
-
17
- console.log('\n๐Ÿ–ฑ๏ธ Real-time cursor position test:');
18
- console.log('Move your mouse to different displays and observe coordinates...');
19
- console.log('Press Ctrl+C to stop\n');
20
-
21
- let lastDisplay = null;
22
- const interval = setInterval(() => {
23
- const pos = recorder.getCursorPosition();
24
-
25
- // Determine which display cursor is on
26
- let currentDisplay = null;
27
- for (const display of displays) {
28
- if (pos.x >= display.x &&
29
- pos.x < display.x + display.width &&
30
- pos.y >= display.y &&
31
- pos.y < display.y + display.height) {
32
- currentDisplay = display;
33
- break;
34
- }
35
- }
36
-
37
- if (currentDisplay && currentDisplay.id !== lastDisplay?.id) {
38
- const type = currentDisplay.isPrimary ? 'PRIMARY' : 'SECONDARY';
39
- console.log(`\n๐Ÿ“ Moved to ${type} Display ${currentDisplay.id}:`);
40
- console.log(` Display bounds: (${currentDisplay.x}, ${currentDisplay.y}) to (${currentDisplay.x + currentDisplay.width}, ${currentDisplay.y + currentDisplay.height})`);
41
- lastDisplay = currentDisplay;
42
- }
43
-
44
- if (currentDisplay) {
45
- // Calculate display-relative coordinates
46
- const displayRelativeX = pos.x - currentDisplay.x;
47
- const displayRelativeY = pos.y - currentDisplay.y;
48
-
49
- const type = currentDisplay.isPrimary ? 'PRI' : 'SEC';
50
- console.log(`${type} | Global: (${pos.x}, ${pos.y}) | Display-rel: (${displayRelativeX}, ${displayRelativeY})`);
51
- } else {
52
- console.log(`??? | Global: (${pos.x}, ${pos.y}) | Not on any display`);
53
- }
54
- }, 200); // Every 200ms
55
-
56
- // Handle Ctrl+C
57
- process.on('SIGINT', () => {
58
- clearInterval(interval);
59
- console.log('\n\n๐Ÿ” Test completed. Look for any unusual patterns in the coordinates.');
60
- console.log('\nKey things to check:');
61
- console.log('1. Do global coordinates look correct on both displays?');
62
- console.log('2. Do display-relative coordinates start from (0,0) on each display?');
63
- console.log('3. Are there any unexpected offsets on the primary display?');
64
- process.exit(0);
65
- });
66
-
67
- } catch (error) {
68
- console.error('โŒ Test failed:', error.message);
69
- }
70
- }
71
-
72
- testDisplayCoordinates().catch(console.error);
@@ -1,120 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const MacRecorder = require('./index.js');
4
- const path = require('path');
5
- const fs = require('fs');
6
-
7
- // Test output directory
8
- const outputDir = './test-output';
9
- if (!fs.existsSync(outputDir)) {
10
- fs.mkdirSync(outputDir, { recursive: true });
11
- }
12
-
13
- const recorder = new MacRecorder();
14
-
15
- async function testIntegratedRecording() {
16
- console.log('๐ŸŽฌ Testing integrated screen recording with automatic cursor tracking...');
17
-
18
- try {
19
- // Test permissions first
20
- const permissions = await recorder.checkPermissions();
21
- console.log('๐Ÿ“‹ Permissions:', permissions);
22
-
23
- if (!permissions.screenRecording) {
24
- console.log('โŒ Screen recording permission required');
25
- return;
26
- }
27
-
28
- // Get displays and windows
29
- const displays = await recorder.getDisplays();
30
- const windows = await recorder.getWindows();
31
-
32
- console.log(`๐Ÿ“บ Found ${displays.length} displays and ${windows.length} windows`);
33
-
34
- // Setup recording options
35
- const timestamp = Date.now();
36
- const videoPath = path.join(outputDir, `integrated-test-${timestamp}.mov`);
37
-
38
- console.log(`๐ŸŽฅ Starting recording to: ${videoPath}`);
39
- console.log('๐Ÿ“ Cursor tracking will start automatically and create a JSON file in the same directory');
40
-
41
- // Start recording (cursor tracking will start automatically)
42
- // Use the primary display (displayId: 1) where cursor is located
43
- await recorder.startRecording(videoPath, {
44
- includeMicrophone: false,
45
- includeSystemAudio: false,
46
- captureCursor: true,
47
- displayId: 1 // Use primary display where cursor is located
48
- });
49
-
50
- console.log('โœ… Recording started successfully!');
51
- console.log('๐Ÿ–ฑ๏ธ Cursor tracking started automatically');
52
- console.log('โฐ Recording for 5 seconds...');
53
- console.log('๐Ÿ’ก Move your mouse around to generate cursor data');
54
-
55
- // Wait for 5 seconds
56
- await new Promise(resolve => setTimeout(resolve, 5000));
57
-
58
- console.log('๐Ÿ›‘ Stopping recording...');
59
-
60
- // Stop recording (cursor tracking will stop automatically)
61
- const result = await recorder.stopRecording();
62
-
63
- console.log('โœ… Recording stopped:', result);
64
- console.log('๐Ÿ“ Checking output files...');
65
-
66
- // Wait a moment for files to be written
67
- await new Promise(resolve => setTimeout(resolve, 1000));
68
-
69
- // Check for video file
70
- if (fs.existsSync(videoPath)) {
71
- const videoStats = fs.statSync(videoPath);
72
- console.log(`๐Ÿ“น Video file created: ${videoPath} (${videoStats.size} bytes)`);
73
- } else {
74
- console.log('โŒ Video file not found');
75
- }
76
-
77
- // Check for cursor file
78
- const files = fs.readdirSync(outputDir);
79
- const cursorFile = files.find(f => f.startsWith('temp_cursor_') && f.endsWith('.json'));
80
-
81
- if (cursorFile) {
82
- const cursorPath = path.join(outputDir, cursorFile);
83
- const cursorStats = fs.statSync(cursorPath);
84
- console.log(`๐Ÿ–ฑ๏ธ Cursor file created: ${cursorFile} (${cursorStats.size} bytes)`);
85
-
86
- // Read and validate cursor data
87
- try {
88
- const cursorData = JSON.parse(fs.readFileSync(cursorPath, 'utf8'));
89
- console.log(`๐Ÿ“Š Cursor data points: ${cursorData.length}`);
90
-
91
- if (cursorData.length > 0) {
92
- const first = cursorData[0];
93
- const last = cursorData[cursorData.length - 1];
94
- console.log(`๐Ÿ“ First cursor position: (${first.x}, ${first.y}) at ${first.timestamp}ms`);
95
- console.log(`๐Ÿ“ Last cursor position: (${last.x}, ${last.y}) at ${last.timestamp}ms`);
96
- console.log(`๐Ÿ“ Coordinate system: ${first.coordinateSystem || 'global'}`);
97
- }
98
- } catch (parseError) {
99
- console.log('โš ๏ธ Could not parse cursor data:', parseError.message);
100
- }
101
- } else {
102
- console.log('โŒ Cursor file not found');
103
- }
104
-
105
- console.log('โœ… Test completed successfully!');
106
-
107
- } catch (error) {
108
- console.error('โŒ Test failed:', error.message);
109
- console.error(error.stack);
110
- }
111
- }
112
-
113
- // Run the test
114
- testIntegratedRecording().then(() => {
115
- console.log('๐Ÿ All tests finished');
116
- process.exit(0);
117
- }).catch(error => {
118
- console.error('๐Ÿ’ฅ Fatal error:', error);
119
- process.exit(1);
120
- });
@@ -1,110 +0,0 @@
1
- const MacRecorder = require('./index.js');
2
-
3
- async function testMenuBarOffset() {
4
- console.log('๐Ÿงช Testing macOS menu bar coordinate offset...');
5
-
6
- const recorder = new MacRecorder();
7
-
8
- try {
9
- const displays = await recorder.getDisplays();
10
- const windows = await recorder.getWindows();
11
-
12
- const primaryDisplay = displays.find(d => d.isPrimary);
13
-
14
- console.log('\n๐Ÿ“ฑ Primary Display Info:');
15
- console.log(` Bounds: (${primaryDisplay.x}, ${primaryDisplay.y}) ${primaryDisplay.width}x${primaryDisplay.height}`);
16
-
17
- // Get menu bar height by checking screen bounds vs usable bounds
18
- const { screen } = require('electron').screen || {};
19
-
20
- // Alternative way to get menu bar info using native macOS APIs
21
- console.log('\n๐Ÿ” Coordinate System Analysis:');
22
-
23
- // Find windows on primary display
24
- const primaryWindows = windows.filter(window => {
25
- const windowCenterX = window.x + window.width / 2;
26
- const windowCenterY = window.y + window.height / 2;
27
- return (windowCenterX >= primaryDisplay.x &&
28
- windowCenterX < primaryDisplay.x + primaryDisplay.width &&
29
- windowCenterY >= primaryDisplay.y &&
30
- windowCenterY < primaryDisplay.y + primaryDisplay.height);
31
- });
32
-
33
- console.log('\n๐ŸชŸ Windows on Primary Display:');
34
- primaryWindows.slice(0, 3).forEach((window, i) => {
35
- console.log(` ${i+1}. "${window.title}" at (${window.x}, ${window.y}) ${window.width}x${window.height}`);
36
-
37
- // Check if window Y starts suspiciously high (indicating menu bar offset)
38
- if (window.y > 20 && window.y < 100) {
39
- console.log(` โš ๏ธ Window Y=${window.y} suggests menu bar offset of ~${window.y}px`);
40
- }
41
- });
42
-
43
- // Test cursor coordinates at the very top of the screen
44
- console.log('\n๐Ÿ–ฑ๏ธ Move mouse to the very TOP of the primary screen and observe:');
45
- console.log('(This will help identify if menu bar affects coordinates)');
46
-
47
- for (let i = 0; i < 10; i++) {
48
- await new Promise(resolve => setTimeout(resolve, 500));
49
- const pos = recorder.getCursorPosition();
50
-
51
- if (pos.x >= primaryDisplay.x &&
52
- pos.x < primaryDisplay.x + primaryDisplay.width &&
53
- pos.y >= primaryDisplay.y &&
54
- pos.y < primaryDisplay.y + primaryDisplay.height) {
55
-
56
- console.log(` Test ${i+1}: Global (${pos.x}, ${pos.y}) | Y from top: ${pos.y - primaryDisplay.y}`);
57
-
58
- // If cursor Y is very close to 0 but not exactly 0, there might be menu bar offset
59
- if (pos.y >= primaryDisplay.y && pos.y <= primaryDisplay.y + 50) {
60
- const yFromTop = pos.y - primaryDisplay.y;
61
- if (yFromTop > 0 && yFromTop < 40) {
62
- console.log(` ๐ŸŽฏ Potential menu bar detected: ${yFromTop}px from top`);
63
- }
64
- }
65
- }
66
- }
67
-
68
- // Test with a specific window on primary display
69
- if (primaryWindows.length > 0) {
70
- const testWindow = primaryWindows[0];
71
-
72
- console.log(`\n๐Ÿงช Testing window coordinate transformation:`);
73
- console.log(` Window: "${testWindow.title}"`);
74
- console.log(` Global position: (${testWindow.x}, ${testWindow.y})`);
75
- console.log(` Display offset: (${testWindow.x - primaryDisplay.x}, ${testWindow.y - primaryDisplay.y})`);
76
-
77
- // Calculate what window-relative coordinates should be
78
- console.log(`\n๐Ÿ“Š Expected coordinate transformation:`);
79
- console.log(` If cursor at window's top-left (${testWindow.x}, ${testWindow.y}):`);
80
- console.log(` Should become window-relative: (0, 0)`);
81
- console.log(` Current transformation would give: (${testWindow.x - testWindow.x}, ${testWindow.y - testWindow.y})`);
82
-
83
- // Check if there's a Y offset issue
84
- const expectedZeroY = testWindow.y - testWindow.y; // Should be 0
85
- if (expectedZeroY !== 0) {
86
- console.log(` โŒ Y transformation issue detected!`);
87
- }
88
-
89
- // Now check what happens with display transformation
90
- const globalToDisplayX = testWindow.x - primaryDisplay.x;
91
- const globalToDisplayY = testWindow.y - primaryDisplay.y;
92
- const displayToWindowX = globalToDisplayX - (testWindow.x - primaryDisplay.x);
93
- const displayToWindowY = globalToDisplayY - (testWindow.y - primaryDisplay.y);
94
-
95
- console.log(`\n๐Ÿ”ง Two-step transformation analysis:`);
96
- console.log(` Step 1 - Global to display-relative: (${globalToDisplayX}, ${globalToDisplayY})`);
97
- console.log(` Step 2 - Display-relative to window-relative: (${displayToWindowX}, ${displayToWindowY})`);
98
-
99
- if (displayToWindowX !== 0 || displayToWindowY !== 0) {
100
- console.log(` โŒ Two-step transformation creates offset!`);
101
- console.log(` โœ… Should use direct transformation: global - window_global`);
102
- }
103
- }
104
-
105
- } catch (error) {
106
- console.error('โŒ Test failed:', error.message);
107
- }
108
- }
109
-
110
- testMenuBarOffset().catch(console.error);
@@ -1 +0,0 @@
1
- [{"x":609,"y":795,"timestamp":184,"unixTimeMs":1758313956779,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":609,"y":795,"timestamp":205,"unixTimeMs":1758313956800,"cursorType":"default","type":"mousedown","coordinateSystem":"display-relative"},{"x":609,"y":795,"timestamp":224,"unixTimeMs":1758313956819,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":609,"y":795,"timestamp":286,"unixTimeMs":1758313956881,"cursorType":"default","type":"mouseup","coordinateSystem":"display-relative"},{"x":609,"y":795,"timestamp":306,"unixTimeMs":1758313956901,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":609,"y":802,"timestamp":824,"unixTimeMs":1758313957419,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":608,"y":812,"timestamp":842,"unixTimeMs":1758313957437,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":605,"y":828,"timestamp":863,"unixTimeMs":1758313957458,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":601,"y":851,"timestamp":883,"unixTimeMs":1758313957478,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":596,"y":877,"timestamp":905,"unixTimeMs":1758313957500,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":594,"y":887,"timestamp":923,"unixTimeMs":1758313957518,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":591,"y":900,"timestamp":942,"unixTimeMs":1758313957537,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":590,"y":905,"timestamp":965,"unixTimeMs":1758313957560,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":589,"y":908,"timestamp":984,"unixTimeMs":1758313957579,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":588,"y":910,"timestamp":1025,"unixTimeMs":1758313957620,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":588,"y":912,"timestamp":1065,"unixTimeMs":1758313957660,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":588,"y":914,"timestamp":1124,"unixTimeMs":1758313957719,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":587,"y":917,"timestamp":1145,"unixTimeMs":1758313957740,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":586,"y":920,"timestamp":1167,"unixTimeMs":1758313957762,"cursorType":"default","type":"move","coordinateSystem":"display-relative"},{"x":586,"y":922,"timestamp":1186,"unixTimeMs":1758313957781,"cursorType":"default","type":"move","coordinateSystem":"display-relative"}