node-mac-recorder 2.10.17 → 2.10.19

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.10.17",
3
+ "version": "2.10.19",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
package/quick-test.js CHANGED
@@ -1,50 +1,35 @@
1
- const MacRecorder = require('./index');
1
+ #!/usr/bin/env node
2
+
3
+ const WindowSelector = require('./window-selector');
2
4
 
3
5
  async function quickTest() {
4
- const recorder = new MacRecorder();
5
-
6
- console.log('🚀 Hızlı Sistem Sesi Testi\n');
7
-
6
+ console.log('🧪 Quick Window Selector Test');
7
+ console.log('============================\n');
8
+
9
+ const selector = new WindowSelector();
10
+
8
11
  try {
9
- // Ses cihazlarını listele
10
- const devices = await recorder.getAudioDevices();
11
- console.log('🎤 Mevcut ses cihazları:');
12
- devices.forEach((d, i) => console.log(`${i+1}. ${d.name}`));
13
-
14
- // Sistem sesi cihazı var mı?
15
- const sysDevice = devices.find(d =>
16
- d.name.toLowerCase().includes('aggregate') ||
17
- d.name.toLowerCase().includes('blackhole') ||
18
- d.name.toLowerCase().includes('soundflower')
19
- );
20
-
21
- if (sysDevice) {
22
- console.log(`\n✅ Sistem sesi cihazı bulundu: ${sysDevice.name}`);
23
- console.log('🎵 Sistem sesi yakalama çalışmalı');
24
- } else {
25
- console.log('\n⚠️ Sistem sesi cihazı yok');
26
- console.log('💡 BlackHole veya Soundflower yüklemen gerekiyor');
27
- }
28
-
29
- // Kısa test kayıt
30
- console.log('\n🔴 2 saniyelik test kayıt başlıyor...');
31
- console.log('🎵 Şimdi müzik çal!');
32
-
33
- await recorder.startRecording('./test-output/quick-test.mov', {
34
- includeSystemAudio: true,
35
- includeMicrophone: false,
36
- systemAudioDeviceId: sysDevice?.id,
37
- captureArea: { x: 0, y: 0, width: 200, height: 150 }
38
- });
39
-
40
- await new Promise(resolve => setTimeout(resolve, 2000));
41
- await recorder.stopRecording();
42
-
43
- console.log('✅ Test tamamlandı! ./test-output/quick-test.mov dosyasını kontrol et');
44
-
12
+ console.log('✅ Starting window selection...');
13
+ console.log('🎯 Hover over windows to see highlighting (no border)');
14
+ console.log('🔒 Window dragging should be blocked');
15
+ console.log('⌛ Test will auto-stop in 15 seconds\n');
16
+
17
+ await selector.startSelection();
18
+
19
+ // Auto stop after 15 seconds
20
+ setTimeout(async () => {
21
+ console.log('\n⏹️ Auto-stopping test...');
22
+ await selector.cleanup();
23
+ process.exit(0);
24
+ }, 15000);
25
+
45
26
  } catch (error) {
46
- console.error('❌ Hata:', error.message);
27
+ console.error('❌ Test failed:', error.message);
28
+ await selector.cleanup();
29
+ process.exit(1);
47
30
  }
48
31
  }
49
32
 
50
- quickTest();
33
+ if (require.main === module) {
34
+ quickTest().catch(console.error);
35
+ }
@@ -60,6 +60,12 @@ void updateScreenOverlays();
60
60
  - (void)setHighlightFrame:(NSRect)frame;
61
61
  @end
62
62
 
63
+ // Custom button with hover effects
64
+ @interface HoverButton : NSButton
65
+ @property (nonatomic) BOOL isHovered;
66
+ - (void)setupHoverTracking;
67
+ @end
68
+
63
69
  @implementation WindowSelectorOverlayView
64
70
 
65
71
  - (instancetype)initWithFrame:(NSRect)frameRect {
@@ -95,16 +101,18 @@ void updateScreenOverlays();
95
101
  xRadius:8.0
96
102
  yRadius:8.0];
97
103
 
98
- // Fill color based on toggle state
104
+ // Fill color and border based on toggle state
99
105
  NSColor *fillColor;
100
106
  NSColor *strokeColor;
101
107
  CGFloat lineWidth;
102
108
 
103
109
  if (self.isToggled) {
110
+ // Locked state: thicker border
104
111
  fillColor = [NSColor colorWithRed:0.6 green:0.4 blue:0.9 alpha:0.4];
105
112
  strokeColor = [NSColor colorWithRed:0.45 green:0.25 blue:0.75 alpha:0.9];
106
113
  lineWidth = 3.0;
107
114
  } else {
115
+ // Normal state: thin border
108
116
  fillColor = [NSColor colorWithRed:0.6 green:0.4 blue:0.9 alpha:0.4];
109
117
  strokeColor = [NSColor whiteColor];
110
118
  lineWidth = 1.0;
@@ -172,6 +180,62 @@ void updateScreenOverlays();
172
180
 
173
181
  @end
174
182
 
183
+ @implementation HoverButton
184
+
185
+ - (instancetype)initWithFrame:(NSRect)frameRect {
186
+ self = [super initWithFrame:frameRect];
187
+ if (self) {
188
+ self.isHovered = NO;
189
+ [self setupHoverTracking];
190
+ }
191
+ return self;
192
+ }
193
+
194
+ - (void)setupHoverTracking {
195
+ NSTrackingArea *trackingArea = [[NSTrackingArea alloc]
196
+ initWithRect:self.bounds
197
+ options:(NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways)
198
+ owner:self
199
+ userInfo:nil];
200
+ [self addTrackingArea:trackingArea];
201
+ }
202
+
203
+ - (void)mouseEntered:(NSEvent *)event {
204
+ self.isHovered = YES;
205
+ [self animateScale:1.2 duration:0.15];
206
+ }
207
+
208
+ - (void)mouseExited:(NSEvent *)event {
209
+ self.isHovered = NO;
210
+ [self animateScale:1.0 duration:0.15];
211
+ }
212
+
213
+ - (void)animateScale:(CGFloat)scale duration:(NSTimeInterval)duration {
214
+ [NSAnimationContext beginGrouping];
215
+ [NSAnimationContext currentContext].duration = duration;
216
+ [NSAnimationContext currentContext].timingFunction =
217
+ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
218
+
219
+ CATransform3D transform = CATransform3DMakeScale(scale, scale, 1.0);
220
+ self.layer.transform = transform;
221
+
222
+ [NSAnimationContext endGrouping];
223
+ }
224
+
225
+ - (void)updateTrackingAreas {
226
+ [super updateTrackingAreas];
227
+
228
+ // Remove old tracking areas
229
+ for (NSTrackingArea *area in self.trackingAreas) {
230
+ [self removeTrackingArea:area];
231
+ }
232
+
233
+ // Add new tracking area
234
+ [self setupHoverTracking];
235
+ }
236
+
237
+ @end
238
+
175
239
  // Recording preview overlay view - full screen with cutout
176
240
  @interface RecordingPreviewView : NSView
177
241
  @property (nonatomic, strong) NSDictionary *recordingWindowInfo;
@@ -1249,8 +1313,8 @@ bool startScreenSelection() {
1249
1313
 
1250
1314
  // Note: NSWindow doesn't have setWantsLayer method, only NSView does
1251
1315
 
1252
- // Create select button with more padding
1253
- NSButton *selectButton = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 200, 60)];
1316
+ // Create select button with more padding and hover effects
1317
+ NSButton *selectButton = [[HoverButton alloc] initWithFrame:NSMakeRect(0, 0, 200, 60)];
1254
1318
  [selectButton setTitle:@"Start Record"];
1255
1319
  [selectButton setButtonType:NSButtonTypeMomentaryPushIn];
1256
1320
  [selectButton setBordered:NO];
@@ -1292,8 +1356,8 @@ bool startScreenSelection() {
1292
1356
  [selectButton setFocusRingType:NSFocusRingTypeNone];
1293
1357
  [selectButton setShowsBorderOnlyWhileMouseInside:NO];
1294
1358
 
1295
- // Create cancel button for screen selection
1296
- NSButton *screenCancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 120, 40)];
1359
+ // Create cancel button for screen selection with hover effects
1360
+ NSButton *screenCancelButton = [[HoverButton alloc] initWithFrame:NSMakeRect(0, 0, 120, 40)];
1297
1361
  [screenCancelButton setTitle:@"Cancel"];
1298
1362
  [screenCancelButton setButtonType:NSButtonTypeMomentaryPushIn];
1299
1363
  [screenCancelButton setBordered:NO];
@@ -1586,6 +1650,14 @@ Napi::Value StartWindowSelection(const Napi::CallbackInfo& info) {
1586
1650
  }
1587
1651
 
1588
1652
  @try {
1653
+ // Clean up any existing overlay first
1654
+ if (g_overlayWindow) {
1655
+ [g_overlayWindow close];
1656
+ g_overlayWindow = nil;
1657
+ g_overlayView = nil;
1658
+ g_selectButton = nil;
1659
+ }
1660
+
1589
1661
  // Get all windows
1590
1662
  g_allWindows = [getAllSelectableWindows() retain];
1591
1663
 
@@ -1642,8 +1714,8 @@ Napi::Value StartWindowSelection(const Napi::CallbackInfo& info) {
1642
1714
  [g_overlayWindow setMovable:NO];
1643
1715
  [g_overlayWindow setMovableByWindowBackground:NO];
1644
1716
 
1645
- // Create select button with purple theme
1646
- g_selectButton = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 200, 60)];
1717
+ // Create select button with purple theme and hover effects
1718
+ g_selectButton = [[HoverButton alloc] initWithFrame:NSMakeRect(0, 0, 200, 60)];
1647
1719
  [g_selectButton setTitle:@"Start Record"];
1648
1720
  [g_selectButton setButtonType:NSButtonTypeMomentaryPushIn];
1649
1721
  [g_selectButton setBordered:NO];
@@ -1683,8 +1755,8 @@ Napi::Value StartWindowSelection(const Napi::CallbackInfo& info) {
1683
1755
  // Add select button directly to window (not view) for proper layering
1684
1756
  [g_overlayWindow.contentView addSubview:g_selectButton];
1685
1757
 
1686
- // Create cancel button
1687
- NSButton *cancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 120, 40)];
1758
+ // Create cancel button with hover effects
1759
+ NSButton *cancelButton = [[HoverButton alloc] initWithFrame:NSMakeRect(0, 0, 120, 40)];
1688
1760
  [cancelButton setTitle:@"Cancel"];
1689
1761
  [cancelButton setButtonType:NSButtonTypeMomentaryPushIn];
1690
1762
  [cancelButton setBordered:NO];