node-mac-recorder 2.6.1 → 2.6.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.6.1",
3
+ "version": "2.6.2",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -30,6 +30,8 @@ static NSMutableArray *g_screenOverlayWindows = nil;
30
30
  static NSDictionary *g_selectedScreenInfo = nil;
31
31
  static NSArray *g_allScreens = nil;
32
32
  static id g_screenKeyEventMonitor = nil;
33
+ static NSTimer *g_screenTrackingTimer = nil;
34
+ static NSInteger g_currentActiveScreenIndex = -1;
33
35
 
34
36
  // Forward declarations
35
37
  void cleanupWindowSelector();
@@ -46,6 +48,7 @@ bool stopScreenSelection();
46
48
  NSDictionary* getSelectedScreenInfo();
47
49
  bool showScreenRecordingPreview(NSDictionary *screenInfo);
48
50
  bool hideScreenRecordingPreview();
51
+ void updateScreenOverlays();
49
52
 
50
53
  // Custom overlay view class
51
54
  @interface WindowSelectorOverlayView : NSView
@@ -139,6 +142,7 @@ bool hideScreenRecordingPreview();
139
142
  // Screen selection overlay view
140
143
  @interface ScreenSelectorOverlayView : NSView
141
144
  @property (nonatomic, strong) NSDictionary *screenInfo;
145
+ @property (nonatomic) BOOL isActiveScreen;
142
146
  @end
143
147
 
144
148
  @implementation ScreenSelectorOverlayView
@@ -151,6 +155,7 @@ bool hideScreenRecordingPreview();
151
155
  // Ensure no borders or decorations
152
156
  self.layer.borderWidth = 0.0;
153
157
  self.layer.cornerRadius = 0.0;
158
+ self.isActiveScreen = NO;
154
159
  }
155
160
  return self;
156
161
  }
@@ -160,12 +165,23 @@ bool hideScreenRecordingPreview();
160
165
 
161
166
  if (!self.screenInfo) return;
162
167
 
163
- // Background with transparency - purple tone (no border)
164
- // Ensure no borders or frames are drawn
165
- [[NSColor colorWithRed:0.5 green:0.3 blue:0.8 alpha:0.3] setFill];
168
+ // Background with transparency - purple tone varies by active state
169
+ if (self.isActiveScreen) {
170
+ // Active screen: brighter, more opaque
171
+ [[NSColor colorWithRed:0.6 green:0.4 blue:0.9 alpha:0.4] setFill];
172
+ } else {
173
+ // Inactive screen: dimmer, less opaque
174
+ [[NSColor colorWithRed:0.4 green:0.2 blue:0.6 alpha:0.25] setFill];
175
+ }
166
176
  NSRectFill(self.bounds);
167
177
 
168
- // Text will be handled by separate label above button
178
+ // Add subtle border for active screen
179
+ if (self.isActiveScreen) {
180
+ [[NSColor colorWithRed:0.7 green:0.5 blue:1.0 alpha:0.6] setStroke];
181
+ NSBezierPath *borderPath = [NSBezierPath bezierPathWithRect:NSInsetRect(self.bounds, 2, 2)];
182
+ [borderPath setLineWidth:4.0];
183
+ [borderPath stroke];
184
+ }
169
185
  }
170
186
 
171
187
  @end
@@ -216,6 +232,10 @@ bool hideScreenRecordingPreview();
216
232
  - (void)timerUpdate:(NSTimer *)timer {
217
233
  updateOverlay();
218
234
  }
235
+
236
+ - (void)screenTimerUpdate:(NSTimer *)timer {
237
+ updateScreenOverlays();
238
+ }
219
239
  @end
220
240
 
221
241
  static WindowSelectorDelegate *g_delegate = nil;
@@ -766,10 +786,106 @@ bool hideRecordingPreview() {
766
786
  }
767
787
  }
768
788
 
789
+ // Update screen overlays based on mouse position
790
+ void updateScreenOverlays() {
791
+ @autoreleasepool {
792
+ if (!g_isScreenSelecting || !g_screenOverlayWindows || !g_allScreens) return;
793
+
794
+ // Get current mouse position
795
+ NSPoint mouseLocation = [NSEvent mouseLocation];
796
+ // Convert from NSEvent coordinates (bottom-left) to screen coordinates
797
+ NSArray *screens = [NSScreen screens];
798
+ NSScreen *mouseScreen = nil;
799
+ NSInteger mouseScreenIndex = -1;
800
+
801
+ // Find which screen contains the mouse
802
+ for (NSInteger i = 0; i < [screens count]; i++) {
803
+ NSScreen *screen = [screens objectAtIndex:i];
804
+ NSRect screenFrame = [screen frame];
805
+
806
+ if (NSPointInRect(mouseLocation, screenFrame)) {
807
+ mouseScreen = screen;
808
+ mouseScreenIndex = i;
809
+ break;
810
+ }
811
+ }
812
+
813
+ // If mouse screen changed, update overlays
814
+ if (mouseScreenIndex != g_currentActiveScreenIndex) {
815
+ g_currentActiveScreenIndex = mouseScreenIndex;
816
+
817
+ // Update all screen overlays
818
+ for (NSInteger i = 0; i < [g_screenOverlayWindows count] && i < [screens count]; i++) {
819
+ NSWindow *overlayWindow = [g_screenOverlayWindows objectAtIndex:i];
820
+ ScreenSelectorOverlayView *overlayView = (ScreenSelectorOverlayView *)[overlayWindow contentView];
821
+
822
+ // Update overlay appearance based on whether it's the active screen
823
+ bool isActiveScreen = (i == mouseScreenIndex);
824
+
825
+ // Update overlay state and appearance
826
+ [overlayView setIsActiveScreen:isActiveScreen];
827
+ [overlayView setNeedsDisplay:YES];
828
+
829
+ // Update UI elements based on active state
830
+ for (NSView *subview in [overlayView subviews]) {
831
+ if ([subview isKindOfClass:[NSButton class]]) {
832
+ NSButton *button = (NSButton *)subview;
833
+ if ([button.title isEqualToString:@"Start Record"]) {
834
+ if (isActiveScreen) {
835
+ // Active screen: bright, prominent button
836
+ [button.layer setBackgroundColor:[[NSColor colorWithRed:0.7 green:0.45 blue:0.9 alpha:1.0] CGColor]];
837
+ [button setAlphaValue:1.0];
838
+ } else {
839
+ // Inactive screen: dimmer button
840
+ [button.layer setBackgroundColor:[[NSColor colorWithRed:0.4 green:0.25 blue:0.55 alpha:0.8] CGColor]];
841
+ [button setAlphaValue:0.7];
842
+ }
843
+ }
844
+ }
845
+ if ([subview isKindOfClass:[NSTextField class]]) {
846
+ NSTextField *label = (NSTextField *)subview;
847
+ if (isActiveScreen) {
848
+ [label setTextColor:[NSColor whiteColor]];
849
+ [label setAlphaValue:1.0];
850
+ } else {
851
+ [label setTextColor:[NSColor colorWithWhite:0.8 alpha:0.8]];
852
+ [label setAlphaValue:0.7];
853
+ }
854
+ }
855
+ if ([subview isKindOfClass:[NSImageView class]]) {
856
+ NSImageView *imageView = (NSImageView *)subview;
857
+ if (isActiveScreen) {
858
+ [imageView setAlphaValue:1.0];
859
+ } else {
860
+ [imageView setAlphaValue:0.6];
861
+ }
862
+ }
863
+ }
864
+
865
+ if (isActiveScreen) {
866
+ NSLog(@"šŸ–„ļø ACTIVE SCREEN: Display %ld", (long)(i + 1));
867
+ }
868
+
869
+ // Bring active screen overlay to front
870
+ if (isActiveScreen) {
871
+ [overlayWindow orderFront:nil];
872
+ [overlayWindow makeKeyAndOrderFront:nil];
873
+ }
874
+ }
875
+ }
876
+ }
877
+ }
878
+
769
879
  // Screen selection functions
770
880
  void cleanupScreenSelector() {
771
881
  g_isScreenSelecting = false;
772
882
 
883
+ // Stop screen tracking timer
884
+ if (g_screenTrackingTimer) {
885
+ [g_screenTrackingTimer invalidate];
886
+ g_screenTrackingTimer = nil;
887
+ }
888
+
773
889
  // Remove key event monitor
774
890
  if (g_screenKeyEventMonitor) {
775
891
  [NSEvent removeMonitor:g_screenKeyEventMonitor];
@@ -790,6 +906,9 @@ void cleanupScreenSelector() {
790
906
  [g_allScreens release];
791
907
  g_allScreens = nil;
792
908
  }
909
+
910
+ // Reset active screen tracking
911
+ g_currentActiveScreenIndex = -1;
793
912
  }
794
913
 
795
914
  bool startScreenSelection() {
@@ -1003,6 +1122,7 @@ bool startScreenSelection() {
1003
1122
  g_allScreens = [screenInfoArray retain];
1004
1123
  [screenInfoArray release];
1005
1124
  g_isScreenSelecting = true;
1125
+ g_currentActiveScreenIndex = -1;
1006
1126
 
1007
1127
  // Add ESC key event monitor to cancel selection
1008
1128
  g_screenKeyEventMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSEventMaskKeyDown
@@ -1013,7 +1133,18 @@ bool startScreenSelection() {
1013
1133
  }
1014
1134
  }];
1015
1135
 
1136
+ // Start screen tracking timer to update overlays based on mouse position
1137
+ if (!g_delegate) {
1138
+ g_delegate = [[WindowSelectorDelegate alloc] init];
1139
+ }
1140
+ g_screenTrackingTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 // 20 FPS
1141
+ target:g_delegate
1142
+ selector:@selector(screenTimerUpdate:)
1143
+ userInfo:nil
1144
+ repeats:YES];
1145
+
1016
1146
  NSLog(@"šŸ–„ļø SCREEN SELECTION: Started with %lu screens (ESC to cancel)", (unsigned long)[screens count]);
1147
+ NSLog(@"šŸ–„ļø SCREEN TRACKING: Timer started for overlay updates");
1017
1148
 
1018
1149
  return true;
1019
1150
 
File without changes
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env node
2
+
3
+ const WindowSelector = require('./window-selector');
4
+
5
+ async function testMultiDisplayOverlay() {
6
+ console.log('šŸ–„ļø Multi-Display Overlay Test');
7
+ console.log('=============================\n');
8
+
9
+ const selector = new WindowSelector();
10
+
11
+ try {
12
+ // Check permissions first
13
+ const permissions = await selector.checkPermissions();
14
+ console.log('šŸ” Permissions:');
15
+ console.log(` Screen Recording: ${permissions.screenRecording ? 'āœ…' : 'āŒ'}`);
16
+ console.log(` Accessibility: ${permissions.accessibility ? 'āœ…' : 'āŒ'}\n`);
17
+
18
+ // Get display information
19
+ const MacRecorder = require('./index');
20
+ const recorder = new MacRecorder();
21
+ const displays = await recorder.getDisplays();
22
+
23
+ console.log(`šŸ–„ļø Found ${displays.length} display(s):`);
24
+ displays.forEach((display, index) => {
25
+ console.log(` Display ${index + 1}: ${display.name} (${display.resolution}) at (${display.x}, ${display.y}) ${display.isPrimary ? '🌟 PRIMARY' : ''}`);
26
+ });
27
+ console.log('');
28
+
29
+ if (displays.length < 2) {
30
+ console.log('āš ļø Only one display detected. Connect a second display to fully test multi-display overlay functionality.');
31
+ console.log('Continuing with single display test...\n');
32
+ }
33
+
34
+ let windowDetectionCount = 0;
35
+ let displaySwitchCount = 0;
36
+ let lastDisplayId = null;
37
+
38
+ // Event listeners for detailed tracking
39
+ selector.on('windowEntered', (window) => {
40
+ windowDetectionCount++;
41
+
42
+ // Try to determine which display this window is on
43
+ let windowDisplayId = null;
44
+ const windowCenterX = window.x + window.width / 2;
45
+ const windowCenterY = window.y + window.height / 2;
46
+
47
+ for (const display of displays) {
48
+ if (windowCenterX >= display.x &&
49
+ windowCenterX < display.x + display.width &&
50
+ windowCenterY >= display.y &&
51
+ windowCenterY < display.y + display.height) {
52
+ windowDisplayId = display.id;
53
+ break;
54
+ }
55
+ }
56
+
57
+ if (windowDisplayId !== lastDisplayId) {
58
+ displaySwitchCount++;
59
+ lastDisplayId = windowDisplayId;
60
+ }
61
+
62
+ const displayName = displays.find(d => d.id === windowDisplayId)?.name || 'Unknown';
63
+
64
+ console.log(`\nšŸŽÆ WINDOW DETECTED #${windowDetectionCount}:`);
65
+ console.log(` App: ${window.appName}`);
66
+ console.log(` Title: "${window.title}"`);
67
+ console.log(` Position: (${window.x}, ${window.y})`);
68
+ console.log(` Size: ${window.width} Ɨ ${window.height}`);
69
+ console.log(` šŸ–„ļø Estimated Display: ${displayName} (ID: ${windowDisplayId})`);
70
+ console.log(` Display switches so far: ${displaySwitchCount}`);
71
+
72
+ if (displays.length > 1) {
73
+ console.log(`\nšŸ’” Multi-Display Test Instructions:`);
74
+ console.log(` • Move cursor to windows on different displays`);
75
+ console.log(` • Overlay should follow cursor across displays`);
76
+ console.log(` • Window detection should work on all displays`);
77
+ }
78
+ });
79
+
80
+ selector.on('windowLeft', (window) => {
81
+ console.log(`\n🚪 LEFT WINDOW: ${window.appName} - "${window.title}"`);
82
+ });
83
+
84
+ selector.on('windowSelected', (selectedWindow) => {
85
+ console.log('\n' + 'šŸŽ‰'.repeat(20));
86
+ console.log('šŸŽÆ WINDOW SELECTED!');
87
+ console.log('šŸŽ‰'.repeat(20));
88
+
89
+ const selectedDisplayName = displays.find(d =>
90
+ selectedWindow.x >= d.x &&
91
+ selectedWindow.x < d.x + d.width &&
92
+ selectedWindow.y >= d.y &&
93
+ selectedWindow.y < d.y + d.height
94
+ )?.name || 'Unknown';
95
+
96
+ console.log(`\nšŸ“Š Selection Results:`);
97
+ console.log(` Selected: ${selectedWindow.appName} - "${selectedWindow.title}"`);
98
+ console.log(` Position: (${selectedWindow.x}, ${selectedWindow.y})`);
99
+ console.log(` Size: ${selectedWindow.width} Ɨ ${selectedWindow.height}`);
100
+ console.log(` Display: ${selectedDisplayName}`);
101
+ console.log(`\nšŸ“ˆ Test Statistics:`);
102
+ console.log(` Total window detections: ${windowDetectionCount}`);
103
+ console.log(` Display switches: ${displaySwitchCount}`);
104
+ console.log(` Multi-display support: ${displaySwitchCount > 0 || displays.length === 1 ? 'āœ…' : 'āŒ'}`);
105
+
106
+ process.exit(0);
107
+ });
108
+
109
+ // Interactive selection with instructions
110
+ console.log('šŸš€ Starting multi-display overlay test...\n');
111
+ console.log('šŸ“‹ Test Instructions:');
112
+ console.log(' 1. Move your cursor to windows on different displays');
113
+ console.log(' 2. Watch for overlay following cursor across displays');
114
+ console.log(' 3. Verify window detection works on all displays');
115
+ console.log(' 4. Press ENTER when you want to select a window');
116
+ console.log(' 5. Press ESC or Ctrl+C to cancel\n');
117
+
118
+ if (displays.length > 1) {
119
+ console.log('šŸ–„ļø Multi-Display Tips:');
120
+ console.log(' • Try windows on both primary and secondary displays');
121
+ console.log(' • Move cursor quickly between displays to test overlay tracking');
122
+ console.log(' • Overlay should appear on the display where the cursor is\n');
123
+ }
124
+
125
+ // Setup manual selection with ENTER key
126
+ const readline = require('readline');
127
+ const rl = readline.createInterface({
128
+ input: process.stdin,
129
+ output: process.stdout
130
+ });
131
+
132
+ rl.on('line', () => {
133
+ // Get current status to see if there's a window under cursor
134
+ const status = selector.getStatus();
135
+ if (status.nativeStatus && status.nativeStatus.currentWindow) {
136
+ selector.emit('windowSelected', status.nativeStatus.currentWindow);
137
+ } else {
138
+ console.log('\nāš ļø No window under cursor. Move cursor over a window first.');
139
+ }
140
+ });
141
+
142
+ await selector.startSelection();
143
+
144
+ // Status monitoring
145
+ let statusCount = 0;
146
+ const statusInterval = setInterval(() => {
147
+ statusCount++;
148
+
149
+ if (statusCount % 40 === 0) { // Every 20 seconds
150
+ console.log(`\nā±ļø Status Update (${statusCount/2}s):`);
151
+ console.log(` Window detections: ${windowDetectionCount}`);
152
+ console.log(` Display switches: ${displaySwitchCount}`);
153
+ console.log(` Current displays: ${displays.length}`);
154
+ if (displays.length > 1) {
155
+ console.log(` Multi-display overlay: ${displaySwitchCount > 0 ? 'āœ… Working' : 'ā³ Waiting for cross-display movement'}`);
156
+ }
157
+ }
158
+ }, 500);
159
+
160
+ // Graceful shutdown
161
+ process.on('SIGINT', async () => {
162
+ clearInterval(statusInterval);
163
+ rl.close();
164
+
165
+ console.log('\n\nšŸ›‘ Test stopped by user');
166
+ console.log('\nšŸ“Š Final Test Results:');
167
+ console.log(` Total window detections: ${windowDetectionCount}`);
168
+ console.log(` Display switches observed: ${displaySwitchCount}`);
169
+ console.log(` Displays available: ${displays.length}`);
170
+ console.log(` Multi-display support: ${displaySwitchCount > 0 || displays.length === 1 ? 'āœ… WORKING' : 'āŒ NEEDS INVESTIGATION'}`);
171
+
172
+ await selector.cleanup();
173
+ console.log('āœ… Cleanup completed');
174
+ process.exit(0);
175
+ });
176
+
177
+ } catch (error) {
178
+ console.error('\nāŒ Test failed:', error.message);
179
+ process.exit(1);
180
+ }
181
+ }
182
+
183
+ if (require.main === module) {
184
+ testMultiDisplayOverlay();
185
+ }
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+
3
+ const WindowSelector = require('./window-selector');
4
+
5
+ async function testMultiScreenSelection() {
6
+ console.log('šŸ–„ļø Multi-Screen Selection Test');
7
+ console.log('==============================\n');
8
+
9
+ const selector = new WindowSelector();
10
+
11
+ try {
12
+ // Check permissions first
13
+ const permissions = await selector.checkPermissions();
14
+ console.log('šŸ” Permissions:');
15
+ console.log(` Screen Recording: ${permissions.screenRecording ? 'āœ…' : 'āŒ'}`);
16
+ console.log(` Accessibility: ${permissions.accessibility ? 'āœ…' : 'āŒ'}\n`);
17
+
18
+ if (!permissions.screenRecording || !permissions.accessibility) {
19
+ console.log('āš ļø Missing required permissions. Please grant permissions in System Preferences.');
20
+ process.exit(1);
21
+ }
22
+
23
+ // Get display information
24
+ const MacRecorder = require('./index');
25
+ const recorder = new MacRecorder();
26
+ const displays = await recorder.getDisplays();
27
+
28
+ console.log(`šŸ–„ļø Found ${displays.length} display(s):`);
29
+ displays.forEach((display, index) => {
30
+ console.log(` Display ${index + 1}: ${display.name} (${display.resolution}) at (${display.x}, ${display.y}) ${display.isPrimary ? '🌟 PRIMARY' : ''}`);
31
+ });
32
+ console.log('');
33
+
34
+ if (displays.length < 2) {
35
+ console.log('āš ļø Only one display detected. Connect a second display to fully test multi-screen selection functionality.');
36
+ console.log('Continuing with single display test...\n');
37
+ } else {
38
+ console.log('āœ… Multiple displays detected. Perfect for multi-screen testing!\n');
39
+ }
40
+
41
+ console.log('šŸš€ Starting multi-screen selection test...\n');
42
+ console.log('šŸ“‹ What to expect:');
43
+ console.log(' 1. Overlay will appear on ALL screens simultaneously');
44
+ console.log(' 2. The screen where your mouse is located will be HIGHLIGHTED (brighter)');
45
+ console.log(' 3. Other screens will be dimmer');
46
+ console.log(' 4. Move mouse between screens to see the highlighting change');
47
+ console.log(' 5. Click "Start Record" on the screen you want to record');
48
+ console.log(' 6. Press ESC to cancel\n');
49
+
50
+ if (displays.length > 1) {
51
+ console.log('šŸ–±ļø Multi-Screen Instructions:');
52
+ console.log(' • Move your mouse from one screen to another');
53
+ console.log(' • Watch the overlay highlighting follow your mouse');
54
+ console.log(' • Notice how the active screen becomes brighter');
55
+ console.log(' • All screens should show the overlay simultaneously\n');
56
+ }
57
+
58
+ console.log('ā±ļø Starting screen selection in 3 seconds...');
59
+ await new Promise(resolve => setTimeout(resolve, 3000));
60
+
61
+ // Start screen selection
62
+ const success = await selector.startScreenSelection();
63
+
64
+ if (!success) {
65
+ console.error('āŒ Failed to start screen selection');
66
+ process.exit(1);
67
+ }
68
+
69
+ console.log('āœ… Screen selection started successfully!');
70
+ console.log('šŸ–±ļø Move your mouse between screens to test highlighting...\n');
71
+
72
+ // Monitor for selection completion
73
+ let checkCount = 0;
74
+ const selectionChecker = setInterval(() => {
75
+ checkCount++;
76
+ const selectedScreen = selector.getSelectedScreen();
77
+
78
+ if (selectedScreen) {
79
+ clearInterval(selectionChecker);
80
+
81
+ console.log('\n' + 'šŸŽ‰'.repeat(25));
82
+ console.log('šŸŽÆ SCREEN SELECTED!');
83
+ console.log('šŸŽ‰'.repeat(25));
84
+
85
+ console.log(`\nšŸ“Š Selected Screen Details:`);
86
+ console.log(` Name: ${selectedScreen.name}`);
87
+ console.log(` Resolution: ${selectedScreen.resolution}`);
88
+ console.log(` Position: (${selectedScreen.x}, ${selectedScreen.y})`);
89
+ console.log(` Size: ${selectedScreen.width} Ɨ ${selectedScreen.height}`);
90
+ console.log(` Primary: ${selectedScreen.isPrimary ? 'Yes' : 'No'}`);
91
+
92
+ console.log(`\nāœ… Multi-screen selection test completed successfully!`);
93
+ console.log(`šŸ“ˆ Test ran for ${(checkCount * 100) / 1000} seconds`);
94
+
95
+ process.exit(0);
96
+ }
97
+
98
+ // Show progress every 5 seconds
99
+ if (checkCount % 50 === 0) {
100
+ const elapsed = (checkCount * 100) / 1000;
101
+ console.log(`ā±ļø Test running for ${elapsed}s - Move mouse between screens to test highlighting`);
102
+
103
+ if (displays.length > 1) {
104
+ console.log('šŸ’” Remember: The overlay should appear on ALL screens, but only the one with your mouse should be bright');
105
+ }
106
+ }
107
+ }, 100); // Check every 100ms
108
+
109
+ // Timeout after 60 seconds
110
+ setTimeout(() => {
111
+ clearInterval(selectionChecker);
112
+ console.log('\nā° Test timeout reached (60 seconds)');
113
+ console.log('šŸ›‘ Stopping screen selection...');
114
+
115
+ selector.stopScreenSelection().then(() => {
116
+ console.log('āœ… Screen selection stopped');
117
+
118
+ if (displays.length > 1) {
119
+ console.log('\nšŸ“Š Multi-Screen Test Summary:');
120
+ console.log(' Expected behavior:');
121
+ console.log(' āœ“ Overlays should have appeared on all screens');
122
+ console.log(' āœ“ Mouse screen should have been highlighted brighter');
123
+ console.log(' āœ“ Non-mouse screens should have been dimmer');
124
+ console.log(' āœ“ Highlighting should have changed as you moved mouse');
125
+ } else {
126
+ console.log('\nšŸ“Š Single-Screen Test Summary:');
127
+ console.log(' āœ“ Overlay should have appeared on your screen');
128
+ console.log(' āœ“ Screen should have been highlighted');
129
+ }
130
+
131
+ process.exit(0);
132
+ }).catch((error) => {
133
+ console.error('āŒ Error stopping screen selection:', error.message);
134
+ process.exit(1);
135
+ });
136
+ }, 60000);
137
+
138
+ // Handle Ctrl+C gracefully
139
+ process.on('SIGINT', async () => {
140
+ clearInterval(selectionChecker);
141
+ console.log('\n\nšŸ›‘ Test interrupted by user');
142
+
143
+ try {
144
+ await selector.stopScreenSelection();
145
+ console.log('āœ… Screen selection stopped');
146
+ } catch (error) {
147
+ console.log('āš ļø Error during cleanup:', error.message);
148
+ }
149
+
150
+ console.log('\nšŸ“Š Test Results Summary:');
151
+ console.log(` Displays available: ${displays.length}`);
152
+ console.log(` Test duration: ${(checkCount * 100) / 1000} seconds`);
153
+ if (displays.length > 1) {
154
+ console.log(' Multi-screen support: Test interrupted before completion');
155
+ }
156
+
157
+ process.exit(0);
158
+ });
159
+
160
+ } catch (error) {
161
+ console.error('\nāŒ Test failed:', error.message);
162
+ if (error.stack) {
163
+ console.error('Stack trace:', error.stack);
164
+ }
165
+ process.exit(1);
166
+ }
167
+ }
168
+
169
+ if (require.main === module) {
170
+ testMultiScreenSelection();
171
+ }