node-mac-recorder 2.17.13 → 2.17.14

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.17.13",
3
+ "version": "2.17.14",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -43,9 +43,9 @@ static NSTimeInterval g_lastCursorCheckTime = 0;
43
43
  static int g_sameCursorDetectionCount = 0;
44
44
  static NSString *g_pendingCursorType = nil;
45
45
 
46
- // Cursor stability constants
47
- static const NSTimeInterval CURSOR_STABILITY_THRESHOLD = 0.1; // 100ms
48
- static const int CURSOR_CONFIRMATION_COUNT = 2; // Need 2 consecutive detections
46
+ // Cursor stability constants - more responsive
47
+ static const NSTimeInterval CURSOR_STABILITY_THRESHOLD = 0.05; // 50ms (faster response)
48
+ static const int CURSOR_CONFIRMATION_COUNT = 1; // Need 1 detection (more responsive)
49
49
 
50
50
  // Mouse button state tracking
51
51
  static bool g_leftMouseDown = false;
@@ -157,13 +157,48 @@ NSString* getCursorType() {
157
157
  [elementRole isEqualToString:@"AXSearchField"]) {
158
158
  contextualCursorType = @"text";
159
159
  }
160
- // POINTER CURSORS - only for interactive elements
160
+ // POINTER CURSORS - interactive elements with broader detection
161
161
  else if ([elementRole isEqualToString:@"AXLink"] ||
162
162
  [elementRole isEqualToString:@"AXButton"] ||
163
163
  [elementRole isEqualToString:@"AXMenuItem"] ||
164
164
  [elementRole isEqualToString:@"AXRadioButton"] ||
165
- [elementRole isEqualToString:@"AXCheckBox"]) {
165
+ [elementRole isEqualToString:@"AXCheckBox"] ||
166
+ [elementRole isEqualToString:@"AXPopUpButton"] ||
167
+ [elementRole isEqualToString:@"AXTab"]) {
166
168
  contextualCursorType = @"pointer";
169
+
170
+ // Also check subroles for links and buttons
171
+ CFStringRef subrole = NULL;
172
+ AXError subroleError = AXUIElementCopyAttributeValue(elementAtPosition, kAXSubroleAttribute, (CFTypeRef*)&subrole);
173
+ if (subroleError == kAXErrorSuccess && subrole) {
174
+ NSString *elementSubrole = (__bridge_transfer NSString*)subrole;
175
+ if ([elementSubrole isEqualToString:@"AXCloseButton"] ||
176
+ [elementSubrole isEqualToString:@"AXMinimizeButton"] ||
177
+ [elementSubrole isEqualToString:@"AXZoomButton"] ||
178
+ [elementSubrole isEqualToString:@"AXToolbarButton"]) {
179
+ contextualCursorType = @"pointer";
180
+ }
181
+ }
182
+ }
183
+ // WEB ELEMENTS - for web links that might not show as AXLink
184
+ else if ([elementRole isEqualToString:@"AXGroup"] ||
185
+ [elementRole isEqualToString:@"AXStaticText"]) {
186
+ // Check if it's clickable/has action
187
+ CFArrayRef actions = NULL;
188
+ AXError actionsError = AXUIElementCopyActionNames(elementAtPosition, &actions);
189
+ if (actionsError == kAXErrorSuccess && actions) {
190
+ CFIndex actionCount = CFArrayGetCount(actions);
191
+ for (CFIndex i = 0; i < actionCount; i++) {
192
+ CFStringRef action = (CFStringRef)CFArrayGetValueAtIndex(actions, i);
193
+ NSString *actionStr = (__bridge NSString*)action;
194
+ if ([actionStr isEqualToString:@"AXPress"] ||
195
+ [actionStr isEqualToString:@"AXShowMenu"]) {
196
+ contextualCursorType = @"pointer";
197
+ break;
198
+ }
199
+ }
200
+ CFRelease(actions);
201
+ }
167
202
  }
168
203
  // WINDOW BORDER RESIZE - critical for resize detection
169
204
  else if ([elementRole isEqualToString:@"AXWindow"]) {
@@ -239,7 +274,7 @@ NSString* getCursorType() {
239
274
  // Layer 3: Intelligent fusion of NSCursor and contextual results
240
275
  NSString *detectedCursorType = @"default";
241
276
 
242
- // Priority logic:
277
+ // Priority logic with better fallback:
243
278
  // 1. If contextual gives resize cursor, always use it (resize has highest priority)
244
279
  if (contextualCursorType != nil &&
245
280
  ([contextualCursorType hasSuffix:@"resize"] ||
@@ -247,14 +282,19 @@ NSString* getCursorType() {
247
282
  [contextualCursorType isEqualToString:@"ns-resize"])) {
248
283
  detectedCursorType = contextualCursorType;
249
284
  }
250
- // 2. If NSCursor gives a definitive answer and no resize context, use it
285
+ // 2. If NSCursor gives a definitive answer, use it
251
286
  else if (nsCursorType != nil) {
252
287
  detectedCursorType = nsCursorType;
253
288
  }
254
- // 3. If NSCursor is nil/unknown, but contextual is available, use contextual
255
- else if (contextualCursorType != nil) {
289
+ // 3. If contextual gives specific non-resize cursor, use it
290
+ else if (contextualCursorType != nil &&
291
+ ![contextualCursorType isEqualToString:@"default"]) {
256
292
  detectedCursorType = contextualCursorType;
257
293
  }
294
+ // 4. If both are nil or default, use true default
295
+ else {
296
+ detectedCursorType = @"default";
297
+ }
258
298
 
259
299
  // Layer 4: Stability filtering to prevent oscillation
260
300