8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

使用 kIOHIDOptionsTypeSeizeDevice 时,按键不会被阻止,并且仍会传递给操作系统

Mikkel 2月前

40 0

我的目标是使用 IOHID 阻止按键到达操作系统(由于其他原因不能使用 CGEvent)。根据 kIOHIDOptionsTypeSeizeDevice 的文档:用于打开独占通信...

我的目标是使用 IOHID 阻止按键到达操作系统(由于其他原因不能使用 CGEvent)。根据 的文档 kIOHIDOptionsTypeSeizeDevice

用于打开与设备的独占通信。这将阻止系统和其他客户端接收来自设备的事件。

#import "TestKeys.h"
#import <IOKit/hid/IOHIDManager.h>
#import <IOKit/hid/IOHIDUsageTables.h>

@implementation TestKeys

#define KEYS 2

static void Handle_InputCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDValueRef value)
{
    IOHIDElementRef elem = IOHIDValueGetElement(value);

    uint16_t scancode = IOHIDElementGetUsage(elem);
    
    if (scancode < 4 || scancode > 231) {
        return;
    }
    
    NSLog(@"Key event received: %d", scancode);
}

static void Handle_DeviceMatchingCallback(void * inContext, IOReturn inResult, void * inSender, IOHIDDeviceRef inIOHIDDeviceRef)
{
    NSLog(@"Connected");
}

static void Handle_RemovalCallback(void * inContext, IOReturn inResult, void * inSender, IOHIDDeviceRef inIOHIDDeviceRef)
{
    NSLog(@"Removed");
}

-(void)start
{
    IOHIDManagerRef manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDManagerOptionNone);
    
    if (CFGetTypeID(manager) != IOHIDManagerGetTypeID()) {
        exit(1);
    }

    int usagePage = kHIDPage_GenericDesktop;
    int usage = kHIDUsage_GD_Keyboard;
    
    CFStringRef keys[KEYS] = {
        CFSTR(kIOHIDDeviceUsagePageKey),
        CFSTR(kIOHIDDeviceUsageKey),
    };
    
    CFNumberRef values[KEYS] = {
        CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usagePage),
        CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usage),
    };
    
    CFDictionaryRef matchingDict = CFDictionaryCreate(kCFAllocatorDefault,
                                                      (const void **) keys, (const void **) values, KEYS,
                                                      &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

    for (int i=0; i<KEYS; i++) {
        CFRelease(keys[i]);
        CFRelease(values[i]);
    }
    
    IOHIDManagerSetDeviceMatching(manager, matchingDict);
    CFRelease(matchingDict);
    
    IOHIDManagerRegisterDeviceMatchingCallback(manager, Handle_DeviceMatchingCallback, NULL);
    IOHIDManagerRegisterDeviceRemovalCallback(manager, Handle_RemovalCallback, NULL);
    IOHIDManagerRegisterInputValueCallback(manager, Handle_InputCallback, NULL);
    
    IOHIDManagerOpen(manager, kIOHIDOptionsTypeSeizeDevice);

    IOHIDManagerScheduleWithRunLoop(manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
@end

该代码运行并设法从操作系统全局查看和打印所有击键,但它似乎 kIOHIDOptionsTypeSeizeDevice 被忽略了,因为击键仍然被传递给 macOS。

编辑: 添加 IOReturn result = 到代码中会暴露错误 -536870207 ,该错误转换为 kIOReturnNotPrivileged 。然后我将 Xcode 方案更改为 root 并能够阻止键盘按键。

这就引出了我的下一个问题,我怎样才能将此代码添加到显然不以 root 权限运行的开发者 ID 应用程序中?

帖子版权声明 1、本帖标题:使用 kIOHIDOptionsTypeSeizeDevice 时,按键不会被阻止,并且仍会传递给操作系统
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Mikkel在本站《objective-c》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 谢谢!如果你想看的话,我在这里写了一个后续问题:.com/questions/70780816/…

  • 很高兴我们在评论中追踪到您的 HID 问题是由于权限问题造成的。

    要在生产/部署中以 root 身份运行代码,您需要设置一个单独的工具作为 启动守护进程 ,并将其配置为在主应用程序向其发送 IPC(通常是 XPC)消息时按需启动。

    首先,您有两个主要选项可以设置启动守护程序:

    • 将守护进程二进制文件嵌入到您的 .app 中,并 SMJobBless 从您的应用代码中调用以将其安装在系统中。这将要求用户输入管理员密码。
    • 安装程序 .pkg,将守护进程二进制文件放置在固定位置(例如下面 /Library/Application Support/YourAppName/ ),并将相应的 launchd plist /Library/LaunchDaemons .

    ,设置启动守护程序时 需要 非常 本系列文章 是一份关于应该做什么和应该避免什么的深入指南。

    还要注意的是, SMJobBless App Store 不允许这样做,因此在那里分发的应用程序根本无法实现这种功能。

  • 我只用非苹果键盘(Logitech)测试过它。顺便说一句,问题中的代码是我使用的唯一代码,如果您想使用另一个 HID 设备进行检查,它可以在您自己的项目中独立运行。

  • 所有 HID 设备(包括第三方设备)都会发生这种情况,还是只有内置 Apple 键盘才会发生这种情况?只是想知道这是否是某种安全功能,可以防止您使系统无法使用。

返回
作者最近主题: