-
Notifications
You must be signed in to change notification settings - Fork 1
/
BluetoothKeyboardEnhancer.c
132 lines (112 loc) · 4.48 KB
/
BluetoothKeyboardEnhancer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// clang -framework IOKit -framework Carbon BluetoothKeyboardEnhancer.c -o BluetoothKeyboardEnhancer
// ./BluetoothKeyboardEnhancer
#include <Carbon/Carbon.h>
#include <IOKit/hid/IOHIDManager.h>
#include <IOKit/hid/IOHIDValue.h>
void TriggerEscKey()
{
CGEventRef event = CGEventCreateKeyboardEvent(NULL, kVK_Escape, true);
CGEventPost(kCGSessionEventTap, event);
CFRelease(event);
}
void TriggerForceQuit()
{
system("osascript -l JavaScript -e \"Application('System Events').processes['Finder'].menuBars[0].menus['Apple'].menuItems['Force Quit…'].click()\" 1>/dev/null");
}
void TriggerForceQuitFrontmostApp()
{
pid_t pid;
ProcessSerialNumber psn;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
GetFrontProcess(&psn);
GetProcessPID(&psn, &pid);
#pragma clang diagnostic pop
killpg(getpgid(pid), SIGTERM);
}
void TriggerEmojiPicker()
{
CGEventRef keyboard_down_event = CGEventCreateKeyboardEvent(NULL, kVK_Space, true);
CGEventRef keyboard_up_event = CGEventCreateKeyboardEvent(NULL, kVK_Space, false);
CGEventSetFlags(keyboard_down_event, kCGEventFlagMaskCommand | kCGEventFlagMaskControl);
CGEventSetFlags(keyboard_up_event, 0);
CGEventPost(kCGHIDEventTap, keyboard_down_event);
CGEventPost(kCGHIDEventTap, keyboard_up_event);
CFRelease(keyboard_down_event);
CFRelease(keyboard_up_event);
}
CFMutableDictionaryRef CreateMatchingDictionary(UInt32 usage_page, UInt32 usage)
{
CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFNumberRef page_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage_page);
CFDictionarySetValue(dictionary, CFSTR(kIOHIDDeviceUsagePageKey), page_number);
CFRelease(page_number);
CFNumberRef usage_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
CFDictionarySetValue(dictionary, CFSTR(kIOHIDDeviceUsageKey), usage_number);
CFRelease(usage_number);
return dictionary;
}
void HIDKeyboardCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value)
{
IOHIDElementRef elem = IOHIDValueGetElement(value);
uint32_t usage_page = IOHIDElementGetUsagePage(elem);
uint32_t usage = IOHIDElementGetUsage(elem);
long pressed = IOHIDValueGetIntegerValue(value);
static int shift_down, ctrl_down, option_down, command_down;
if (usage_page == kHIDPage_KeyboardOrKeypad) {
switch (usage) {
case kHIDUsage_KeyboardLeftShift:
case kHIDUsage_KeyboardRightShift:
shift_down = pressed;
break;
case kHIDUsage_KeyboardLeftControl:
ctrl_down = pressed;
break;
case kHIDUsage_KeyboardLeftAlt:
case kHIDUsage_KeyboardRightAlt:
option_down = pressed;
break;
case kHIDUsage_KeyboardLeftGUI:
case kHIDUsage_KeyboardRightGUI:
command_down = pressed;
break;
}
if (ctrl_down && command_down && usage == -1 && pressed == 0x10101010101 /*1103823438081*/) {
TriggerEmojiPicker();
}
}
if (usage_page == kHIDPage_Consumer && usage == kHIDUsage_Csmr_ACHome && pressed == 1) {
if (option_down && command_down) {
if (shift_down) {
TriggerForceQuitFrontmostApp();
} else {
TriggerForceQuit();
}
} else {
TriggerEscKey();
}
}
}
bool CheckAccessibility()
{
#ifdef MAC_OS_X_VERSION_10_9
const void* keys[] = { (void*)kAXTrustedCheckOptionPrompt };
const void* vals[] = { (void*)kCFBooleanTrue };
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, vals, 1, NULL, NULL);
return AXIsProcessTrustedWithOptions(options);
#else
return AXAPIEnabled();
#endif
}
int main()
{
IOHIDManagerRef hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
CFMutableDictionaryRef matching_dictionary = CreateMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
IOHIDManagerSetDeviceMatching(hid_manager, matching_dictionary);
IOHIDManagerRegisterInputValueCallback(hid_manager, HIDKeyboardCallback, NULL);
IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone);
if (CheckAccessibility()) {
CFRunLoopRun();
}
}