You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用IOHIDManager无法在部分macOS设备检测触控板事件

macOS 检测鼠标/触控板事件与设备详情的问题

问题概述

需要在macOS上检测鼠标事件并获取对应设备的详细信息(如厂商ID、产品ID)。当前基于IOHIDManager的代码能检测外接鼠标事件,但无法识别内置触控板事件,且该问题仅出现在部分新机型的Sonoma系统上。

设备兼容性情况

代码正常运行的设备

  • Intel MacBook Pro(Ventura系统)
  • M1 MacBook Pro(Ventura系统)
  • M1 MacBook Pro(Sonoma 14.3系统)

代码失效的设备

  • M3 MacBook Pro(Sonoma 14.6系统)
  • M2 MacBook Air(Sonoma 14.4系统)

现有IOHIDManager代码及问题

以下代码仅能捕获外接鼠标事件,无法响应内置触控板操作:

#include <iostream>
#include <IOKit/hid/IOHIDManager.h>
#include <CoreFoundation/CoreFoundation.h>

void mouseEventCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) {
    std::cout << "Mouse event" << std::endl; // 仅打印外接鼠标事件,内置触控板无响应
}

int main() {
    IOHIDManagerRef manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
    
    // 创建鼠标和触控板的匹配字典
    CFMutableDictionaryRef matchingDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
        &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    
    // 添加匹配条件:通用桌面控制页,鼠标(2)和触控板(5)
    CFDictionaryAddValue(matchingDict, CFSTR(kIOHIDDeviceUsagePageKey), CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, (const int[]){1}));
    CFDictionaryAddValue(matchingDict, CFSTR(kIOHIDDeviceUsageKey), CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, (const int[]){2, 5}));

    // 设置匹配规则
    IOHIDManagerSetDeviceMatching(manager, matchingDict);
    
    // 注册输入值变化回调
    IOHIDManagerRegisterInputValueCallback(manager, mouseEventCallback, NULL);
    
    // 打开HID管理器
    IOHIDManagerOpen(manager, kIOHIDOptionsTypeNone);
    
    // 将HID管理器加入当前运行循环
    IOHIDManagerScheduleWithRunLoop(manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
    
    // 启动循环监听事件
    CFRunLoopRun();
    
    // 资源清理
    CFRelease(matchingDict);
    CFRelease(manager);
    
    return 0;
}

编译命令:

clang++ -o mouse mouse.cpp -framework IOKit -framework CoreFoundation

尝试过的其他方案

  1. manymouse库:问题依旧,无法捕获内置触控板事件。
  2. IOHIDManagerRegisterDeviceMatchingCallback:能识别外接鼠标和触控板设备,但无法捕获触控板的事件。
  3. CGEventTapCreate:可在所有设备上检测到触控板和外接鼠标的事件,但无法获取事件对应的设备详情(如厂商ID、产品ID),代码如下:
// 此代码可捕获所有鼠标/触控板事件,但无法获取设备信息
#include <iostream>
#include <ApplicationServices/ApplicationServices.h>

// 事件回调函数
CGEventRef eventTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* userInfo) {

    if (type == kCGEventLeftMouseDown || type == kCGEventRightMouseDown || type == kCGEventOtherMouseDown) {
        CGPoint mouseLocation = CGEventGetLocation(event);
        std::cout << "鼠标点击位置: (" << mouseLocation.x << ", " << mouseLocation.y << ")" << std::endl;
    }
    else if (type == kCGEventScrollWheel) {
        // 滚轮事件
        CGPoint scrollDelta = CGEventGetUnflippedLocation(event);
        std::cout << "鼠标滚动位置: (" << scrollDelta.x << ", " << scrollDelta.y << ")" << std::endl;
    }

    return event;
}

int main() {
    // 创建事件监听掩码,包含点击和滚轮事件
    CGEventMask eventMask = CGEventMaskBit(kCGEventLeftMouseDown) |
                            CGEventMaskBit(kCGEventRightMouseDown) |
                            CGEventMaskBit(kCGEventOtherMouseDown) |
                            CGEventMaskBit(kCGEventScrollWheel);

    CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, eventMask, eventTapCallback, nullptr);
    if (!eventTap) {
        std::cerr << "创建事件监听失败。" << std::endl;
        return 1;
    }

    // 创建运行循环源并加入当前循环
    CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
    CFRelease(runLoopSource);

    // 启用事件监听
    CGEventTapEnable(eventTap, true);

    // 启动运行循环处理事件
    CFRunLoopRun();

    return 0;
}

解决思路

针对新机型Sonoma系统上内置触控板无法被IOHIDManager捕获的问题,可尝试以下方向:

  1. 调整HID设备匹配规则:Sonoma对内置触控板的HID报告可能有变更,尝试单独匹配触控板的Usage Page/Usage,或添加额外的匹配条件(如设备类型、厂商ID)。
  2. 设备枚举与事件监听结合:先通过IOHIDManagerRegisterDeviceMatchingCallback枚举到内置触控板设备,再针对该设备单独注册输入回调,而非全局注册。
  3. 检查权限设置:确保应用已获得“输入监控”权限(系统设置-隐私与安全性-输入监控),新系统对权限的管控更严格,可能导致内置设备事件无法被捕获。
  4. CGEvent与IOHID信息关联:用CGEventTap捕获事件,同时提前枚举所有HID设备并缓存其信息,尝试通过事件属性关联到对应的设备。

内容的提问来源于stack exchange,提问作者Himaprasoon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 08:12:08