node-mac-recorder 2.20.4 → 2.20.6
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/cursor_tracker.mm +41 -74
package/package.json
CHANGED
package/src/cursor_tracker.mm
CHANGED
|
@@ -106,7 +106,7 @@ static BOOL CopyAttributeBoolean(AXUIElementRef element, CFStringRef attribute,
|
|
|
106
106
|
return YES;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
static BOOL ElementHasAction(AXUIElementRef element, CFStringRef action) {
|
|
109
|
+
static __attribute__((unused)) BOOL ElementHasAction(AXUIElementRef element, CFStringRef action) {
|
|
110
110
|
if (!element || !action) {
|
|
111
111
|
return NO;
|
|
112
112
|
}
|
|
@@ -248,13 +248,7 @@ static NSString* CursorTypeFromAccessibilityElement(AXUIElementRef element, CGPo
|
|
|
248
248
|
CFRelease(valueAttribute);
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
|
|
252
|
-
return @"progress";
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (StringEqualsAny(role, @[@"AXHelpTag", @"AXTooltip"])) {
|
|
256
|
-
return @"help";
|
|
257
|
-
}
|
|
251
|
+
// Leave progress/help to system cursor; don't force via AX
|
|
258
252
|
|
|
259
253
|
if ([role isEqualToString:@"AXSplitter"]) {
|
|
260
254
|
NSString *orientation = CopyAttributeString(element, CFSTR("AXOrientation"));
|
|
@@ -273,11 +267,11 @@ static NSString* CursorTypeFromAccessibilityElement(AXUIElementRef element, CGPo
|
|
|
273
267
|
}
|
|
274
268
|
}
|
|
275
269
|
|
|
276
|
-
|
|
270
|
+
// Pointer (hand) only for actual links; buttons remain default arrow on macOS
|
|
271
|
+
if (StringEqualsAny(role, @[@"AXLink"])) {
|
|
277
272
|
return @"pointer";
|
|
278
273
|
}
|
|
279
|
-
|
|
280
|
-
if (StringEqualsAny(subrole, @[@"AXLink", @"AXToolbarButton", @"AXFileDrop", @"AXDropTarget"])) {
|
|
274
|
+
if (StringEqualsAny(subrole, @[@"AXLink"])) {
|
|
281
275
|
return @"pointer";
|
|
282
276
|
}
|
|
283
277
|
|
|
@@ -295,11 +289,7 @@ static NSString* CursorTypeFromAccessibilityElement(AXUIElementRef element, CGPo
|
|
|
295
289
|
}
|
|
296
290
|
}
|
|
297
291
|
|
|
298
|
-
|
|
299
|
-
ElementHasAction(element, kAXShowMenuAction) ||
|
|
300
|
-
ElementHasAction(element, CFSTR("AXConfirm"))) {
|
|
301
|
-
return @"pointer";
|
|
302
|
-
}
|
|
292
|
+
// Actions alone do not imply pointer hand on macOS; ignore
|
|
303
293
|
|
|
304
294
|
CFTypeRef urlValue = NULL;
|
|
305
295
|
if (AXUIElementCopyAttributeValue(element, kAXURLAttribute, &urlValue) == kAXErrorSuccess && urlValue) {
|
|
@@ -310,23 +300,37 @@ static NSString* CursorTypeFromAccessibilityElement(AXUIElementRef element, CGPo
|
|
|
310
300
|
CFRelease(urlValue);
|
|
311
301
|
}
|
|
312
302
|
|
|
313
|
-
|
|
314
|
-
if (CopyAttributeBoolean(element, CFSTR("AXDraggable"), &isDraggable) && isDraggable) {
|
|
315
|
-
return @"grab";
|
|
316
|
-
}
|
|
303
|
+
// Grab/open-hand often comes from system cursor; avoid forcing via AX
|
|
317
304
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
305
|
+
// Zoom is rare; prefer system cursor unless explicitly needed
|
|
306
|
+
|
|
307
|
+
return nil;
|
|
308
|
+
}
|
|
322
309
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
if (
|
|
327
|
-
return
|
|
310
|
+
static AXUIElementRef CopyParent(AXUIElementRef element) {
|
|
311
|
+
if (!element) return NULL;
|
|
312
|
+
AXUIElementRef parent = NULL;
|
|
313
|
+
if (AXUIElementCopyAttributeValue(element, kAXParentAttribute, (CFTypeRef *)&parent) == kAXErrorSuccess && parent) {
|
|
314
|
+
return parent; // retained
|
|
328
315
|
}
|
|
316
|
+
if (parent) CFRelease(parent);
|
|
317
|
+
return NULL;
|
|
318
|
+
}
|
|
329
319
|
|
|
320
|
+
static NSString* CursorTypeFromElementOrAncestors(AXUIElementRef element, CGPoint cursorPos, int maxDepth) {
|
|
321
|
+
AXUIElementRef current = element;
|
|
322
|
+
int depth = 0;
|
|
323
|
+
while (current && depth < maxDepth) {
|
|
324
|
+
NSString *t = CursorTypeFromAccessibilityElement(current, cursorPos);
|
|
325
|
+
if (t && [t length] > 0) {
|
|
326
|
+
return t;
|
|
327
|
+
}
|
|
328
|
+
AXUIElementRef parent = CopyParent(current);
|
|
329
|
+
if (current != element) CFRelease(current);
|
|
330
|
+
current = parent;
|
|
331
|
+
depth++;
|
|
332
|
+
}
|
|
333
|
+
if (current && current != element) CFRelease(current);
|
|
330
334
|
return nil;
|
|
331
335
|
}
|
|
332
336
|
|
|
@@ -348,7 +352,7 @@ static NSString* detectCursorTypeUsingAccessibility(CGPoint cursorPos) {
|
|
|
348
352
|
AXUIElementRef elementAtPosition = NULL;
|
|
349
353
|
AXError error = AXUIElementCopyElementAtPosition(systemWide, cursorPos.x, cursorPos.y, &elementAtPosition);
|
|
350
354
|
if (error == kAXErrorSuccess && elementAtPosition) {
|
|
351
|
-
cursorType =
|
|
355
|
+
cursorType = CursorTypeFromElementOrAncestors(elementAtPosition, cursorPos, 6);
|
|
352
356
|
CFRelease(elementAtPosition);
|
|
353
357
|
}
|
|
354
358
|
|
|
@@ -359,7 +363,7 @@ static NSString* detectCursorTypeUsingAccessibility(CGPoint cursorPos) {
|
|
|
359
363
|
AXError hitError = AXUIElementCopyParameterizedAttributeValue(systemWide, kAXHitTestParameterizedAttribute, pointValue, (CFTypeRef *)&hitElement);
|
|
360
364
|
CFRelease(pointValue);
|
|
361
365
|
if (hitError == kAXErrorSuccess && hitElement) {
|
|
362
|
-
cursorType =
|
|
366
|
+
cursorType = CursorTypeFromElementOrAncestors(hitElement, cursorPos, 6);
|
|
363
367
|
CFRelease(hitElement);
|
|
364
368
|
}
|
|
365
369
|
}
|
|
@@ -559,51 +563,13 @@ NSString* getCursorType() {
|
|
|
559
563
|
@autoreleasepool {
|
|
560
564
|
g_cursorTypeCounter++;
|
|
561
565
|
|
|
566
|
+
// Use only the system cursor type for live detection.
|
|
562
567
|
NSString *systemCursorType = detectSystemCursorType();
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
CGPoint cursorPos = CGPointZero;
|
|
567
|
-
|
|
568
|
-
CGEventRef event = CGEventCreate(NULL);
|
|
569
|
-
if (event) {
|
|
570
|
-
cursorPos = CGEventGetLocation(event);
|
|
571
|
-
hasCursorPosition = YES;
|
|
572
|
-
CFRelease(event);
|
|
568
|
+
if (systemCursorType && [systemCursorType length] > 0) {
|
|
569
|
+
NSLog(@"🎯 FINAL CURSOR TYPE (System): %@", systemCursorType);
|
|
570
|
+
return systemCursorType;
|
|
573
571
|
}
|
|
574
|
-
|
|
575
|
-
if (!hasCursorPosition) {
|
|
576
|
-
if ([NSThread isMainThread]) {
|
|
577
|
-
cursorPos = [NSEvent mouseLocation];
|
|
578
|
-
hasCursorPosition = YES;
|
|
579
|
-
} else {
|
|
580
|
-
__block CGPoint fallbackPos = CGPointZero;
|
|
581
|
-
dispatch_sync(dispatch_get_main_queue(), ^{
|
|
582
|
-
fallbackPos = [NSEvent mouseLocation];
|
|
583
|
-
});
|
|
584
|
-
cursorPos = fallbackPos;
|
|
585
|
-
hasCursorPosition = YES;
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
if (hasCursorPosition) {
|
|
590
|
-
axCursorType = detectCursorTypeUsingAccessibility(cursorPos);
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
NSString *finalType = nil;
|
|
594
|
-
if (axCursorType && ![axCursorType isEqualToString:@"default"]) {
|
|
595
|
-
finalType = axCursorType;
|
|
596
|
-
} else if (systemCursorType && [systemCursorType length] > 0) {
|
|
597
|
-
// Prefer the system cursor when accessibility reports a generic value.
|
|
598
|
-
finalType = systemCursorType;
|
|
599
|
-
} else if (axCursorType && [axCursorType length] > 0) {
|
|
600
|
-
finalType = axCursorType;
|
|
601
|
-
} else {
|
|
602
|
-
finalType = @"default";
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
NSLog(@"🎯 FINAL CURSOR TYPE: %@", finalType);
|
|
606
|
-
return finalType;
|
|
572
|
+
return @"default";
|
|
607
573
|
}
|
|
608
574
|
}
|
|
609
575
|
|
|
@@ -658,6 +624,7 @@ CGEventRef eventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef eve
|
|
|
658
624
|
NSTimeInterval timestamp = [currentDate timeIntervalSinceDate:g_trackingStartTime] * 1000; // milliseconds
|
|
659
625
|
NSTimeInterval unixTimeMs = [currentDate timeIntervalSince1970] * 1000; // unix timestamp in milliseconds
|
|
660
626
|
NSString *cursorType = getCursorType();
|
|
627
|
+
// (already captured above)
|
|
661
628
|
NSString *eventType = @"move";
|
|
662
629
|
|
|
663
630
|
// Event tipini belirle
|