Number of OSX keys pressed without access

I found that upwork.app can read keystrokes without access, but I cannot figure out how to do this.

I read a lot of topics like this: OSX: Detect system-wide KeyDown events? All topics say that the process should be trusted with “Enable access for assistive devices”, and I cannot find how upwork.app can track keys without this. This is the official documentation for event tracking: https://developer.apple.com/reference/appkit/nsevent/1535472-addglobalmonitorforeventsmatchin From the docs - "Key events can only be tracked if accessibility is enabled or if your application trust accessibility accessibility (see AXIsProcessTrusted).

The apple mail list says the following: http://lists.apple.com/archives/carbon-dev/2010/Feb/msg00043.html I think upwork.app uses some hacks.

How can I read keystrokes without access?

+5
source share
1 answer

Still have not received an answer in the comments, but since it may help other people in the future, I decided to answer anyway.

With IOKit, you can detect that there is a device on the keyboard and receive key events, such as device events. I used this to detect joystick events, but it should work well with keyboards. I assume that the modifications I made are sufficient and should work, however, my Xcode is being updated now, so I have not been able to test it yet.

KeyboardWatcher.h File:

#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 

KeyboardWatcher.m File:

 #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 

If you want to determine which unique identifier is the key, you can use these enumerations (instead of importing Carbon, you can simply create the CGKeyboardMapping.h file and paste them there): fooobar.com/questions/100187 / ...

Finally, to use it, you just need to do this to start viewing keyboard events:

 [[KeyboardWatcher sharedWatcher] startWatching]; 

Get the number of keys pressed using:

 [[KeyboardWatcher sharedWatcher] keysPressedCount]; 

And to stop:

 [[KeyboardWatcher sharedWatcher] stopWatching]; 

These were my links to my original joystick code:

As soon as the update is completed, I will run the code and let me know if it works or not.

EDIT: Just tested and working. Remember to add the IOKit infrastructure to the project.

+4
source

Source: https://habr.com/ru/post/1257506/


All Articles