OSX计数按键没有辅助功能访问

spl*_*oid 7 macos objective-c

我发现upwork.app可以计算没有辅助功能访问的按键,但我无法理解它是如何完成的.

我读了很多像这样的主题: OSX:检测系统范围的keyDown事件? 在所有主题中都说应该信任"允许辅助设备访问"的过程,我无法找到upwork.app如何在没有这个的情况下跟踪密钥.这是跟踪事件的官方文档:https: //developer.apple.com/reference/appkit/nsevent/1535472-addglobalmonitorforeventsmatchin 来自docs - "如果启用了辅助功能或者您的应用程序受信任,则只能监视与键相关的事件辅助功能访问(请参阅AXIsProcessTrusted)."

在苹果邮件列表中说的相同: http ://lists.apple.com/archives/carbon-dev/2010/Feb/msg00043.html我认为upwork.app使用了一些黑客.

如何计算没有辅助功能访问权限的按键?

vit*_*rmm 6

仍然没有在评论中收到你的答案,但由于这可能也有助于其他人在未来我决定回答.

使用IOKit,您可以检测到键盘上有设备,并获取设备事件等按键事件.我用它来检测操纵杆事件,但它应该与键盘一起使用.我假设我所做的修改已经足够并且应该可以工作,但是我的Xcode现在正在更新,所以我还没能测试它.

KeyboardWatcher.h文件:

#import <Foundation/Foundation.h>
#import <IOKit/hid/IOHIDManager.h>
#import <IOKit/hid/IOHIDKeys.h>

@interface KeyboardWatcher : NSObject{
   IOHIDManagerRef HIDManager;
}

@property (nonatomic) int keysPressedCount;

+(instancetype)sharedWatcher;
-(void)startWatching;
-(void)stopWatching;

@end
Run Code Online (Sandbox Code Playgroud)

KeyboardWatcher.m文件:

#import "KeyboardWatcher.h"

@implementation KeyboardWatcher

static KeyboardWatcher *_sharedWatcher;

+(instancetype)sharedWatcher {
    @synchronized([self class]) {
        if (!_sharedWatcher){
            _sharedWatcher = [[KeyboardWatcher alloc] init];
        }
        return _sharedWatcher;
    }
    return nil;
}
-(instancetype)init {
    self = [super init];
    if (self){
        self.keysPressedCount = 0;
    }
    return self;
}

-(void)startWatching {
    [self watchDevicesOfType:kHIDUsage_GD_Keyboard];
}
-(void)watchDevicesOfType:(UInt32)deviceType {
    // Create an HID Manager
    HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);

    // Create a Matching Dictionary
    CFMutableDictionaryRef matchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks,
                                                                                         &kCFTypeDictionaryValueCallBacks);

    // That will make the app just return the computer keyboards
    CFDictionarySetValue(matchDict, CFSTR(kIOHIDPrimaryUsageKey), CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &deviceType));

    // Register the Matching Dictionary to the HID Manager
    IOHIDManagerSetDeviceMatching(HIDManager, matchDict);

    // Register the HID Manager on our app’s run loop
    IOHIDManagerScheduleWithRunLoop(HIDManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode);

    // Open the HID Manager
    IOReturn IOReturn = IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone);

    // Register input calls to Handle_DeviceEventCallback function
    IOHIDManagerRegisterInputValueCallback(HIDManager, Handle_DeviceEventCallback, nil);

    if (IOReturn) NSLog(@"IOHIDManagerOpen failed.");
}
-(void)stopWatching {
    HIDManager = NULL;
}

static void Handle_DeviceEventCallback (void *inContext, IOReturn inResult, void *inSender, IOHIDValueRef value){
    IOHIDElementRef element = IOHIDValueGetElement(value);          // Keyboard pressed key

    uint32_t uniqueIdentifier = IOHIDElementGetCookie(element);     // Unique ID of key
    int elementValue = (int)IOHIDValueGetIntegerValue(value);       // Actual state of key (1=pressed)

    NSLog(@"Unique ID = %u; Value = %d", uniqueIdentifier, elementValue);

    if (elementValue == 1) KeyboardWatcher.sharedWatcher.keysPressedCount++;
}

@end
Run Code Online (Sandbox Code Playgroud)

如果您想要确定哪个唯一ID是哪个键,您可以使用这些枚举(而不是导入Carbon,您只需创建一个CGKeyboardMapping.h文件并将其粘贴到那里):https: //stackoverflow.com/a/16125341/4370893

最后,为了使用它,您只需要这样做就可以开始观看键盘事件了:

[[KeyboardWatcher sharedWatcher] startWatching];
Run Code Online (Sandbox Code Playgroud)

获得按键次数:

[[KeyboardWatcher sharedWatcher] keysPressedCount];
Run Code Online (Sandbox Code Playgroud)

那要停下来:

[[KeyboardWatcher sharedWatcher] stopWatching];
Run Code Online (Sandbox Code Playgroud)

这些是我编写原始操纵杆代码的参考:

一旦更新完成,我将测试代码并确认它是否正常工作.

编辑:刚刚测试过,它正在运行.不要忘记将IOKit框架添加到项目中.