How to create my own modifier key using HID on OSX Sierra - objective-c

Recently Karabiner (the great OSX remapping tool) stopped working on Sierra.
I just read that it is possible to remap keys with HID and I tried the example code below, which remaps a and b. However it's not clear how to create my own modifier key (say Modifier-X), for example TAB to Modifier-X.
Then create mappings such as TAB+X -> Launch Program X , etc...
Karabiner supported this, now Karabiner does not work, so I am trying to find another way to make this happen.
Any suggestions how can this be implemented with HID ?
#import <Foundation/Foundation.h>
#import <IOKit/hidsystem/IOHIDEventSystemClient.h>
#import <IOKit/hidsystem/IOHIDServiceClient.h>
#import <IOKit/hid/IOHIDUsageTables.h>
int main(int argc, char *argv[])
{
IOHIDEventSystemClientRef system;
CFArrayRef services;
uint64_t aKey = 0x700000004;
uint64_t bKey = 0x700000005;
NSArray *map = #[
#{#kIOHIDKeyboardModifierMappingSrcKey:#(aKey),
#kIOHIDKeyboardModifierMappingDstKey:#(aKey)},
#{#kIOHIDKeyboardModifierMappingSrcKey:#(bKey),
#kIOHIDKeyboardModifierMappingDstKey:#(bKey)},
];
system = IOHIDEventSystemClientCreateSimpleClient(kCFAllocatorDefault);
services = IOHIDEventSystemClientCopyServices(system);
for(CFIndex i = 0; i < CFArrayGetCount(services); i++) {
IOHIDServiceClientRef service = (IOHIDServiceClientRef)CFArrayGetValueAtIndex(services, i);
if(IOHIDServiceClientConformsTo(service, kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard)) {
IOHIDServiceClientSetProperty(service, CFSTR(kIOHIDUserKeyUsageMapKey), (CFArrayRef)map);
}
}
CFRelease(services);
CFRelease(system);
return 0;
}

Related

How to change mouse settings programmatically in macOS using IOKit

The functions IOHIDGetAccelerationWithKey and IOHIDSetAccelerationWithKey are deprecated since macOS 10.12, therefore I am trying to implement the same using other IO*-methods.
I have never worked with IOKit, thus, all I can do is google for functions and try to get it to work.
Now I found this: Can't edit IORegistryEntry which has an example of how to change TrackpadThreeFingerSwipe property, however it is using a function which is not defined for me: getEVSHandle. Googling for it reveals only that it should be Found in the MachineSettings framework, however I can't seem to add any "MachineSettings" framework in Xcode 11.
What should I do? Current code is like:
#import <Foundation/Foundation.h>
#import <IOKit/hidsystem/IOHIDLib.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSInteger value = -65536;
CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberNSIntegerType, &value);
CFMutableDictionaryRef propertyDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, NULL, NULL);
CFDictionarySetValue(propertyDict, #"HIDMouseAcceleration", number);
io_connect_t connect = getEVSHandle(); // ???
if (!connect)
{
NSLog(#"Unable to get EVS handle");
}
res = IOConnectSetCFProperties(connect, propertyDict);
if (res != KERN_SUCCESS)
{
NSLog(#"Failed to set mouse acceleration (%d)", res);
}
IOObjectRelease(service);
CFRelease(propertyDict);
}
return 0;
}
The following works (tested with Xcode 11.2 / macOS 10.15)
#import <Foundation/Foundation.h>
#import <IOKit/hidsystem/IOHIDLib.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
io_service_t service = IORegistryEntryFromPath(kIOMasterPortDefault,
kIOServicePlane ":/IOResources/IOHIDSystem");
NSDictionary *parameters = (__bridge NSDictionary *)IORegistryEntryCreateCFProperty(service,
CFSTR(kIOHIDParametersKey), kCFAllocatorDefault, kNilOptions);
NSLog(#"%#", parameters);
NSMutableDictionary *newParameters = [parameters mutableCopy];
newParameters[#"HIDMouseAcceleration"] = #(12345);
kern_return_t result = IORegistryEntrySetCFProperty(service,
CFSTR(kIOHIDParametersKey), (__bridge CFDictionaryRef)newParameters);
NSLog(kIOReturnSuccess == result ? #"Updated" : #"Failed");
IOObjectRelease(service);
}
return 0;
}

Window list from AXUIElementRef always null on High Sierra

After "upgrading" to macOS High Sierra it seems that some code that used to work does no longer. My goal here is just to list out the windows owned by an application. Here is an example:
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#import <ApplicationServices/ApplicationServices.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
pid_t myPID = 311;
AXUIElementRef appRef = AXUIElementCreateApplication(myPID);
CFArrayRef windowList;
AXUIElementCopyAttributeValue(appRef, kAXWindowsAttribute, (CFTypeRef *)&windowList);
}
return 0;
}
The issue here specifically is that windowList does not get contain anything no matter what I do. I have tried multiple PIDs, building/running both debug and release builds, and running them with sudo as well.
Any ideas?

Cocoa / OS X: Determine whether the currently selected keyboard has a numeric keypad

How do you determine the PHYSICAL type / layout of a keyboard attached to a Mac? I'm trying to determine whether the currently selected keyboard has a numeric keypad, but can't see an obvious kTISPropertyXXXXXXX to identify the number of keys / layout, a bit of example code.
#import <Foundation/Foundation.h>
#import <Carbon/Carbon.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
TISInputSourceRef currentKeyLayoutRef;
currentKeyLayoutRef = TISCopyCurrentKeyboardInputSource();
NSLog(#"Basic Info: keyboard_type=%u, layoutName=%#, localizedName=%#, languages: %#\n",
LMGetKbdType(),
TISGetInputSourceProperty(currentKeyLayoutRef, kTISPropertyInputSourceID),
TISGetInputSourceProperty(currentKeyLayoutRef, kTISPropertyLocalizedName),
TISGetInputSourceProperty(currentKeyLayoutRef, kTISPropertyInputSourceLanguages)
);
// NSLog(#"List: %#", TISGetInputSourceProperty(currentKeyLayoutRef, kTISPropertyUnicodeKeyLayoutData));
}
return 0;
}
Any ideas?

How to list devices connected to Mac's USB ports?

How do I list the devices connected to the mac and get their /dev/tty things in Objective C?
I would really love to do this for an application that I've been building for the past day or so.
I need to list the devices connected to the mac, and find one that will suit my criteria for this application. How do I find the devices, and list their /dev/tty's as NSStrings in a list?
Finding and Accessing Devices will get you additional information.
The header file Mounter.h
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/mount.h>
#interface Mounter : NSObject {
struct statfs *buf;
int i, count;
#private
}
-(void) getMountList;
#end
The implementation Mounter.m file:
#import "Mounter.h"
#implementation Mounter
-(void) getMountList {
NSFileManager *fm = [NSFileManager defaultManager];
count = getmntinfo(&buf, 0);
for (i=0; i<count; i++)
{
NSString *path = [NSString stringWithUTF8String:buf[i].f_mntonname];
NSLog(#"Drivers: %#", path);
}

CoreMidi.framework sending midi commands

there is an app called FreeStyler, that you can control using midi commands. In my mac app I want to send midi signals.
Can someone show an example of this?
Elijah
This is what it took to send a note to my blofeld synth. I hope it helps. You can use MIDIObjectGetProperties to find the uniqueIDs for all the midi devices connected to your mac.
#import <Foundation/Foundation.h>
#import <CoreMIDI/CoreMIDI.h>
MIDIEndpointRef getEndpointWithUniqueID(MIDIUniqueID id){
MIDIObjectRef endPoint;
MIDIObjectType foundObj;
MIDIObjectFindByUniqueID(id, &endPoint, &foundObj);
return (MIDIEndpointRef) endPoint;
}
MIDIClientRef getMidiClient(){
MIDIClientRef midiClient;
NSString *outPortName =#"blofeldOut";
MIDIClientCreate((CFStringRef)outPortName, NULL, NULL, &midiClient);
return midiClient;
}
MIDIPortRef getOutPutPort(){
MIDIPortRef outPort;
NSString *outPortName =#"blofeldOut";
MIDIOutputPortCreate(getMidiClient(), (CFStringRef)outPortName, &outPort);
return outPort;
}
MIDIPacketList getMidiPacketList(){
MIDIPacketList packetList;
packetList.numPackets = 1;
MIDIPacket* firstPacket = &packetList.packet[0];
firstPacket->timeStamp = 0; // send immediately
firstPacket->length = 3;
firstPacket->data[0] = 0x90;
firstPacket->data[1] = 60;
firstPacket->data[2] = 64;
// TODO: add end note sequence
return packetList;
}
void play_note(void) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
MIDIPacketList packetList=getMidiPacketList();
MIDIUniqueID blofeldEndpointID = -934632258;
MIDIEndpointRef blofeldEndpoint = getEndpointWithUniqueID(blofeldEndpointID);
MIDISend(getOutPutPort(), blofeldEndpoint, &packetList);
MIDIEndpointDispose(blofeldEndpoint);
[pool drain];
}
int main (int argc, const char * argv[]) {
play_note();
return 0;
}
Your application will need to use the CoreMIDI framework to send or receive MIDI, which I can tell you from experience is not a lot of fun to work with directly. You might want to try the vvopensource framework, which is a MIDI framework designed for cocoa.