node-mac-recorder 2.6.1 ā 2.6.3
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 +1 -1
- package/src/window_selector.mm +146 -4
- package/test-audio-controls.js +0 -0
- package/test-multi-display-overlay.js +185 -0
- package/test-multi-screen-selection.js +171 -0
package/package.json
CHANGED
package/src/window_selector.mm
CHANGED
|
@@ -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
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
//
|
|
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,109 @@ 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
|
+
// Log active screen changes for debugging (optional)
|
|
866
|
+
if (isActiveScreen) {
|
|
867
|
+
NSLog(@"š„ļø Active screen: Display %ld", (long)(i + 1));
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// Ensure ALL overlays are visible, but active one is on top
|
|
871
|
+
[overlayWindow orderFront:nil];
|
|
872
|
+
if (isActiveScreen) {
|
|
873
|
+
[overlayWindow makeKeyAndOrderFront:nil];
|
|
874
|
+
} else {
|
|
875
|
+
[overlayWindow orderFront:nil]; // Keep inactive screens visible too
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
769
882
|
// Screen selection functions
|
|
770
883
|
void cleanupScreenSelector() {
|
|
771
884
|
g_isScreenSelecting = false;
|
|
772
885
|
|
|
886
|
+
// Stop screen tracking timer
|
|
887
|
+
if (g_screenTrackingTimer) {
|
|
888
|
+
[g_screenTrackingTimer invalidate];
|
|
889
|
+
g_screenTrackingTimer = nil;
|
|
890
|
+
}
|
|
891
|
+
|
|
773
892
|
// Remove key event monitor
|
|
774
893
|
if (g_screenKeyEventMonitor) {
|
|
775
894
|
[NSEvent removeMonitor:g_screenKeyEventMonitor];
|
|
@@ -790,6 +909,9 @@ void cleanupScreenSelector() {
|
|
|
790
909
|
[g_allScreens release];
|
|
791
910
|
g_allScreens = nil;
|
|
792
911
|
}
|
|
912
|
+
|
|
913
|
+
// Reset active screen tracking
|
|
914
|
+
g_currentActiveScreenIndex = -1;
|
|
793
915
|
}
|
|
794
916
|
|
|
795
917
|
bool startScreenSelection() {
|
|
@@ -993,9 +1115,14 @@ bool startScreenSelection() {
|
|
|
993
1115
|
[overlayView addSubview:screenInfoLabel];
|
|
994
1116
|
[overlayView addSubview:selectButton];
|
|
995
1117
|
[overlayView addSubview:screenCancelButton];
|
|
1118
|
+
|
|
996
1119
|
[overlayWindow orderFront:nil];
|
|
997
1120
|
[overlayWindow makeKeyAndOrderFront:nil];
|
|
998
1121
|
|
|
1122
|
+
// Additional visibility settings
|
|
1123
|
+
[overlayWindow setAlphaValue:1.0];
|
|
1124
|
+
[overlayWindow setIsVisible:YES];
|
|
1125
|
+
|
|
999
1126
|
[g_screenOverlayWindows addObject:overlayWindow];
|
|
1000
1127
|
[screenInfo release];
|
|
1001
1128
|
}
|
|
@@ -1003,6 +1130,7 @@ bool startScreenSelection() {
|
|
|
1003
1130
|
g_allScreens = [screenInfoArray retain];
|
|
1004
1131
|
[screenInfoArray release];
|
|
1005
1132
|
g_isScreenSelecting = true;
|
|
1133
|
+
g_currentActiveScreenIndex = -1;
|
|
1006
1134
|
|
|
1007
1135
|
// Add ESC key event monitor to cancel selection
|
|
1008
1136
|
g_screenKeyEventMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSEventMaskKeyDown
|
|
@@ -1013,7 +1141,21 @@ bool startScreenSelection() {
|
|
|
1013
1141
|
}
|
|
1014
1142
|
}];
|
|
1015
1143
|
|
|
1144
|
+
// Start screen tracking timer to update overlays based on mouse position
|
|
1145
|
+
if (!g_delegate) {
|
|
1146
|
+
g_delegate = [[WindowSelectorDelegate alloc] init];
|
|
1147
|
+
}
|
|
1148
|
+
g_screenTrackingTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 // 20 FPS
|
|
1149
|
+
target:g_delegate
|
|
1150
|
+
selector:@selector(screenTimerUpdate:)
|
|
1151
|
+
userInfo:nil
|
|
1152
|
+
repeats:YES];
|
|
1153
|
+
|
|
1154
|
+
// Initial update to set correct highlighting
|
|
1155
|
+
updateScreenOverlays();
|
|
1156
|
+
|
|
1016
1157
|
NSLog(@"š„ļø SCREEN SELECTION: Started with %lu screens (ESC to cancel)", (unsigned long)[screens count]);
|
|
1158
|
+
NSLog(@"š„ļø SCREEN TRACKING: Timer started for overlay updates");
|
|
1017
1159
|
|
|
1018
1160
|
return true;
|
|
1019
1161
|
|
package/test-audio-controls.js
CHANGED
|
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
|
+
}
|