Use VirtualHIDDevice for keyboards and mice

This commit is contained in:
Tasos Sahanidis
2018-07-30 00:14:40 +03:00
parent b1f9213d4a
commit 60da97c22f
14 changed files with 1179 additions and 524 deletions
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>16G1314</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>VirtualHIDDevice</string>
<key>CFBundleIdentifier</key>
<string>org.pqrs.driver.Karabiner.VirtualHIDDevice.v060800</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>VirtualHIDDevice</string>
<key>CFBundlePackageType</key>
<string>KEXT</string>
<key>CFBundleShortVersionString</key>
<string>6.8.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>6.8.0</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>9C40b</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<key>DTSDKBuild</key>
<string>17C76</string>
<key>DTSDKName</key>
<string>macosx10.13</string>
<key>DTXcode</key>
<string>0920</string>
<key>DTXcodeBuild</key>
<string>9C40b</string>
<key>IOKitPersonalities</key>
<dict>
<key>VirtualHIDRoot</key>
<dict>
<key>CFBundleIdentifier</key>
<string>org.pqrs.driver.Karabiner.VirtualHIDDevice.v060800</string>
<key>IOClass</key>
<string>org_pqrs_driver_Karabiner_VirtualHIDDevice_VirtualHIDRoot_v060800</string>
<key>IOKitDebug</key>
<integer>0</integer>
<key>IOMatchCategory</key>
<string>org_pqrs_driver_Karabiner_VirtualHIDDevice_VirtualHIDRoot_v060800</string>
<key>IOProviderClass</key>
<string>IOResources</string>
<key>IOResourceMatch</key>
<string>IOKit</string>
<key>IOUserClientClass</key>
<string>org_pqrs_driver_Karabiner_VirtualHIDDevice_VirtualHIDRoot_UserClient_v060800</string>
</dict>
</dict>
<key>OSBundleLibraries</key>
<dict>
<key>com.apple.iokit.IOHIDFamily</key>
<string>2.0.0</string>
<key>com.apple.kpi.bsd</key>
<string>13.0.0</string>
<key>com.apple.kpi.iokit</key>
<string>13.0.0</string>
<key>com.apple.kpi.libkern</key>
<string>13.0.0</string>
<key>com.apple.kpi.mach</key>
<string>13.0.0</string>
</dict>
</dict>
</plist>
@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>files</key>
<dict/>
<key>files2</key>
<dict/>
<key>rules</key>
<dict>
<key>^Resources/</key>
<true/>
<key>^Resources/.*\.lproj/</key>
<dict>
<key>optional</key>
<true/>
<key>weight</key>
<real>1000</real>
</dict>
<key>^Resources/.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
<key>^Resources/Base\.lproj/</key>
<dict>
<key>weight</key>
<real>1010</real>
</dict>
<key>^version.plist$</key>
<true/>
</dict>
<key>rules2</key>
<dict>
<key>.*\.dSYM($|/)</key>
<dict>
<key>weight</key>
<real>11</real>
</dict>
<key>^(.*/)?\.DS_Store$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>2000</real>
</dict>
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
<dict>
<key>nested</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^.*</key>
<true/>
<key>^Info\.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>20</real>
</dict>
<key>^PkgInfo$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>20</real>
</dict>
<key>^Resources/</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
<key>^Resources/.*\.lproj/</key>
<dict>
<key>optional</key>
<true/>
<key>weight</key>
<real>1000</real>
</dict>
<key>^Resources/.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
<key>^Resources/Base\.lproj/</key>
<dict>
<key>weight</key>
<real>1010</real>
</dict>
<key>^[^/]+$</key>
<dict>
<key>nested</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^embedded\.provisionprofile$</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
<key>^version\.plist$</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
</dict>
</dict>
</plist>
+2 -1
View File
@@ -89,6 +89,7 @@ if (MACOS OR LINUX)
firmware.h
includes.h
input.h
input_mac_vhid.h
keymap.h
keymap_patch.h
led.h
@@ -105,7 +106,7 @@ if (MACOS)
PRIVATE
usb_mac.c
input_mac.c
input_mac_mouse.c
input_mac_mouse_legacy.c
extra_mac.c
keymap_mac.h)
elseif (LINUX)
+89 -367
View File
@@ -3,299 +3,88 @@
#include "input.h"
#ifdef OS_MAC
#ifndef OS_MAC_LEGACY
#include <errno.h>
#include <sys/sysctl.h>
#include "input_mac_vhid.h"
int osx_ver = -1;
// VirtualHIDKeyboard
vhid_kbinput kbinput_key = {1, {0}, 0, {{0}}};
vhid_kbinput kbinput_consumer = {2, {0}, 0, {{0}}};
vhid_kbinput kbinput_avtopcase = {3, {0}, 0, {{0}}};
vhid_kbinput kbinput_vendor = {4, {0}, 0, {{0}}};
//vhid_kbconsumerinput kbinput_consumer = {2, {{0}}};
//vhid_kbavtopcaseinput kbinput_avtopcase = {3, {{0}}};
// Numpad keys have an extra flag
#define IS_NUMPAD(scancode) ((scancode) >= kVK_ANSI_KeypadDecimal && (scancode) <= kVK_ANSI_Keypad9 && (scancode) != kVK_ANSI_KeypadClear && (scancode) != kVK_ANSI_KeypadEnter)
pthread_mutex_t _euid_guard = PTHREAD_MUTEX_INITIALIZER;
// Event helpers
static void postevent(io_connect_t event, UInt32 type, NXEventData* ev, IOOptionBits flags, IOOptionBits options, int silence_errors){
// Hack #1: IOHIDPostEvent will fail with kIOReturnNotPrivileged if the event doesn't originate from the UID that owns /dev/console
// You'd think being root would be good enough. You'd be wrong. ckb-daemon needs to run as root for other reasons though
// (namely, being able to seize the physical IOHIDDevices) so what we do instead is change our EUID to the appropriate owner,
// post the event, and then change it right back.
// Yeah...
uid_t uid = 0;
gid_t gid = 0;
struct stat file;
if(!stat("/dev/console", &file)){
uid = file.st_uid;
gid = file.st_gid;
}
IOGPoint location = {0, 0};
// Sierra or higher doesn't need this
if(osx_ver < 16){
if((options & kIOHIDSetRelativeCursorPosition) && type != NX_MOUSEMOVED){
// Hack #2: IOHIDPostEvent will not accept relative mouse coordinates for any event other than NX_MOUSEMOVED
// So we need to get the current absolute coordinates from CoreGraphics and then modify those...
// No longer required in macOS >= 10.12
CGEventRef cge = CGEventCreate(nil);
CGPoint loc = CGEventGetLocation(cge);
CFRelease(cge);
location.x = floor(loc.x + ev->mouseMove.dx);
location.y = floor(loc.y + ev->mouseMove.dy);
options = (options & ~kIOHIDSetRelativeCursorPosition) | kIOHIDSetCursorPosition;
}
}
euid_guard_start;
if(uid != 0)
seteuid(uid);
if(gid != 0)
setegid(gid);
kern_return_t res = IOHIDPostEvent(event, type, location, ev, kNXEventDataVersion, flags | NX_NONCOALSESCEDMASK, options);
if(res != kIOReturnSuccess && !silence_errors)
ckb_warn("Post event failed: %x\n", res);
if(uid != 0)
seteuid(0);
if(gid != 0)
setegid(0);
euid_guard_stop;
}
// Keypress
#define aux_key_data(scancode, down, is_repeat) ((scancode) << 16 | ((down) ? 0x0a00 : 0x0b00) | !!(is_repeat))
static void postevent_kp(io_connect_t event, int kbflags, int scancode, int down, int is_flags, int is_repeat){
NXEventData kp;
memset(&kp, 0, sizeof(kp));
UInt32 type;
IOOptionBits flags = kbflags;
IOOptionBits options = 0;
if(scancode == KEY_CAPSLOCK){
// Caps lock emits NX_FLAGSCHANGED when pressed, but also NX_SYSDEFINED on both press and release
kp.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
kp.compound.misc.L[0] = aux_key_data(NX_KEYTYPE_CAPS_LOCK, down, is_repeat);
postevent(event, NX_SYSDEFINED, &kp, flags, options, 1);
if(!down)
return;
memset(&kp, 0, sizeof(kp));
}
if(IS_MEDIA(scancode)){
kp.compound.subType = (scancode != KEY_POWER ? NX_SUBTYPE_AUX_CONTROL_BUTTONS : NX_SUBTYPE_POWER_KEY);
kp.compound.misc.L[0] = aux_key_data(scancode - KEY_MEDIA, down, is_repeat);
type = NX_SYSDEFINED;
} else {
if(is_flags){
// Modifier (shift, ctrl, etc)
type = NX_FLAGSCHANGED;
options = kIOHIDSetGlobalEventFlags;
} else
// Standard key
type = down ? NX_KEYDOWN : NX_KEYUP;
kp.key.repeat = is_repeat;
kp.key.keyCode = scancode;
kp.key.origCharSet = kp.key.charSet = NX_ASCIISET;
if(IS_NUMPAD(scancode))
flags |= NX_NUMERICPADMASK;
else if(scancode == kVK_Help)
flags |= NX_HELPMASK;
}
postevent(event, type, &kp, flags, options, !down || is_repeat);
// Don't print errors on key up or key repeat ^
}
// Mouse button
static void postevent_mb(io_connect_t event, int button, int down){
NXEventData mb;
memset(&mb, 0, sizeof(mb));
mb.compound.subType = NX_SUBTYPE_AUX_MOUSE_BUTTONS;
mb.compound.misc.L[0] = (1 << button);
mb.compound.misc.L[1] = down ? (1 << button) : 0;
postevent(event, NX_SYSDEFINED, &mb, 0, 0, !down);
// Mouse presses actually generate two events, one with a bitfield of buttons, one with a button number
memset(&mb, 0, sizeof(mb));
UInt32 type;
mb.mouse.buttonNumber = button;
switch(button){
case 0:
type = down ? NX_LMOUSEDOWN : NX_LMOUSEUP;
break;
case 1:
type = down ? NX_RMOUSEDOWN : NX_RMOUSEUP;
break;
default:
type = down ? NX_OMOUSEDOWN : NX_OMOUSEUP;
}
if(down)
mb.mouse.pressure = 255;
postevent(event, type, &mb, 0, 0, 1);
}
// input_mac_mouse.c
extern void wheel_accel(io_connect_t event, int* deltaAxis1, SInt32* fixedDeltaAxis1, SInt32* pointDeltaAxis1);
extern void mouse_accel(io_connect_t event, int* x, int* y);
// Mouse wheel
static void postevent_wheel(io_connect_t event, int scroll_rate, int value){
NXEventData mm;
memset(&mm, 0, sizeof(mm));
if(scroll_rate == SCROLL_ACCELERATED){
wheel_accel(event, &value, &mm.scrollWheel.fixedDeltaAxis1, &mm.scrollWheel.pointDeltaAxis1);
mm.scrollWheel.deltaAxis1 = value;
} else {
// If acceleration is disabled, use a fixed delta
mm.scrollWheel.deltaAxis1 = value * scroll_rate;
}
postevent(event, NX_SCROLLWHEELMOVED, &mm, 0, 0, 0);
}
// Mouse axis
static void postevent_mm(io_connect_t event, int x, int y, int use_accel, uchar buttons){
NXEventData mm;
memset(&mm, 0, sizeof(mm));
UInt32 type = NX_MOUSEMOVED;
if(use_accel)
mouse_accel(event, &x, &y);
mm.mouseMove.dx = x;
mm.mouseMove.dy = y;
if(buttons != 0){
// If a button is pressed, the event type changes
if(buttons & 1)
type = NX_LMOUSEDRAGGED;
else if(buttons & 2)
type = NX_RMOUSEDRAGGED;
else
type = NX_OMOUSEDRAGGED;
// Pick the button index based on the lowest-numbered button
int button = 0;
while(!(buttons & 1)){
button++;
buttons >>= 1;
}
mm.mouse.pressure = 255;
mm.mouse.buttonNumber = button;
}
postevent(event, type, &mm, 0, kIOHIDSetRelativeCursorPosition, 1);
}
// Key repeat delay helper (result in ns)
long repeattime(io_connect_t event, int first){
long delay = 0;
CFTypeRef cf;
kern_return_t param = IOHIDCopyCFTypeParameter(event, (first ? CFSTR(kIOHIDInitialKeyRepeatKey) : CFSTR(kIOHIDKeyRepeatKey)), &cf);
if(param != KERN_SUCCESS)
return -1;
if(!CFNumberGetValue(cf, kCFNumberLongType, &delay))
return -1;
return delay;
}
// Send keyup events for every scancode in the keymap
void clearkeys(usbdevice* kb){
for(int key = 0; key < N_KEYS_INPUT; key++){
int scan = kb->keymap[key].scan;
if((scan & SCAN_SILENT) || scan == BTN_WHEELUP || scan == BTN_WHEELDOWN || IS_MEDIA(scan))
continue;
postevent_kp(kb->event, 0, scan, 0, 0, 0);
}
}
// Opens HID service. Returns kIOReturnSuccess on success.
static int open_iohid(io_connect_t* connection){
char osx_version_buf[256];
size_t size = sizeof(osx_version_buf);
sysctlbyname("kern.osrelease", osx_version_buf, &size, NULL, 0);
char osx_version[3];
strncpy(osx_version, osx_version_buf, 2);
osx_ver = atoi(osx_version);
io_iterator_t iter;
io_service_t service;
// Open master port (if not done yet)
static mach_port_t master = 0;
kern_return_t res;
if(!master && (res = IOMasterPort(bootstrap_port, &master)) != kIOReturnSuccess){
master = 0;
ckb_err("Unable to open master port: 0x%08x\n", res);
goto failure;
}
// Open the HID service
if((res = IOServiceGetMatchingServices(master, IOServiceMatching(kIOHIDSystemClass), &iter)) != kIOReturnSuccess)
goto failure;
service = IOIteratorNext(iter);
if(!service){
res = kIOReturnNotOpen;
goto failure_release_iter;
}
if((res = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, connection)) != kIOReturnSuccess){
*connection = 0;
goto failure_release_iter;
}
// Finished; release objects and return success
IOObjectRelease(service);
failure_release_iter:
IOObjectRelease(iter);
failure:
return res;
}
// VirtualHIDPointing
vhid_mouseinput mouseinput = {{0}, 0, 0, 0, 0};
int os_inputopen(usbdevice* kb){
// The IO service isn't always ready at startup, so if it's not, wait until it is
IOReturn res;
while((res = open_iohid(&kb->event)) != kIOReturnSuccess){
if(res != kIOReturnNotOpen){
// If this is a more serious error, at least print a warning
ckb_err("Unable to open HID system: 0x%08x\n", res);
sleep(1);
continue;
// Check if Karabiner VirtualHIDDevice is loaded
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceNameMatching(VIRTUAL_HID_ROOT_NAME));
if(!service)
ckb_fatal("Unable to open VirtualHIDDevice\n");
kern_return_t kr;
kr = IOServiceOpen(service, mach_task_self(), kIOHIDServerConnectType, &(kb->event));
if(kr != KERN_SUCCESS)
ckb_fatal("IOServiceOpen for VirtualHIDKeyboard error\n");
kr = IOServiceOpen(service, mach_task_self(), kIOHIDServerConnectType, &(kb->event_mouse));
if(kr != KERN_SUCCESS)
ckb_fatal("IOServiceOpen for VirtualHIDPointing error\n");
vhid_properties properties = {0};
kr = IOConnectCallStructMethod(kb->event,
initialize_virtual_hid_keyboard,
&properties, sizeof(vhid_properties),
NULL, 0);
if(kr != KERN_SUCCESS)
ckb_fatal("VirtualHIDKeyboard init error\n");
while(1){
ckb_info("Waiting for VirtualHIDKeyboard...\n");
bool ready = false;
size_t readysize = sizeof(ready);
kr = IOConnectCallStructMethod(kb->event,
is_virtual_hid_keyboard_ready,
NULL, 0,
&ready, &readysize);
if (kr != KERN_SUCCESS) {
ckb_err("VirtualHIDKeyboard not ready yet\n");
} else {
if(ready){
ckb_info("VirtualHIDKeyboard ready\n");
break;
}
}
clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec) {.tv_nsec = 10000000}, NULL);
}
clearkeys(kb);
/* MOUSE */
kr = IOConnectCallStructMethod(kb->event_mouse,
initialize_virtual_hid_pointing,
NULL, 0,
NULL, 0);
if(kr != KERN_SUCCESS)
ckb_fatal("VirtualHIDPointing init error %x\n", kr);
clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec) {.tv_nsec = 10000000}, NULL);
return 0;
}
void os_inputclose(usbdevice* kb){
if(kb->event){
clearkeys(kb);
IOServiceClose(kb->event);
kb->event = 0;
}
}
// Starts/stops key-repeat timer as appropriate
static void setkrtimer(usbdevice* kb){
if(kb->lastkeypress == KEY_NONE)
CFRunLoopRemoveTimer(kb->input_loop, kb->krtimer, kCFRunLoopCommonModes);
else
CFRunLoopAddTimer(kb->input_loop, kb->krtimer, kCFRunLoopCommonModes);
}
// Retrigger the last-pressed key
static void _keyretrigger(usbdevice* kb){
int scancode = kb->lastkeypress;
postevent_kp(kb->event, kb->modifiers, scancode, 1, 0, 1);
// Set next key repeat time
long repeat = repeattime(kb->event, 0);
if(repeat > 0)
timespec_add(&kb->keyrepeat, repeat);
else
kb->lastkeypress = KEY_NONE;
}
void keyretrigger(CFRunLoopTimerRef timer, void* info){
usbdevice* kb = info;
// Repeat the key as many times as needed to catch up
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
while(!(kb->lastkeypress & (SCAN_SILENT | SCAN_MOUSE)) && timespec_ge(time, kb->keyrepeat))
_keyretrigger(kb);
setkrtimer(kb);
}
// Unlike Linux, OSX keyboards have independent caps lock states. This means they're set by the driver itself so we don't poll for external events.
// However, updating indicator state requires locking dmutex and we never want to do that in the input thread.
// Instead, we launch a single-shot thread to update the state.
@@ -318,110 +107,42 @@ static void* indicator_update(void* context){
}
void os_keypress(usbdevice* kb, int scancode, int down){
// Trigger any pending repeats first
keyretrigger(NULL, kb);
// Key/button pressed
if(scancode & SCAN_MOUSE){
if(scancode == BTN_WHEELUP){
if(scancode == BTN_WHEELUP || scancode == BTN_WHEELDOWN) {
mouseinput.vertical_wheel = (down ? ((scancode == BTN_WHEELUP) ? 1 : -1) : 0);
} else {
int scan = (scancode & ~SCAN_MOUSE);
if(down)
postevent_wheel(kb->event, kb->scroll_rate, 1);
return;
} else if(scancode == BTN_WHEELDOWN){
if(down)
postevent_wheel(kb->event, kb->scroll_rate, -1);
return;
add_to_buttons(scan, &mouseinput);
else
remove_from_buttons(scan, &mouseinput);
}
int button = scancode & ~SCAN_MOUSE;
// Reverse or collapse left/right buttons if the system preferences say so
int mode;
if(IOHIDGetMouseButtonMode(kb->event, &mode) == kIOReturnSuccess){
if(mode == kIOHIDButtonMode_ReverseLeftRightClicks && button == 0)
button = 1;
else if(mode != kIOHIDButtonMode_EnableRightClick && button == 1)
button = 0;
}
postevent_mb(kb->event, button, down);
if(down)
kb->mousestate |= (1 << button);
else
kb->mousestate &= ~(1 << button);
IOConnectCallStructMethod(kb->event_mouse, post_pointing_input_report, &mouseinput, sizeof(mouseinput), NULL, 0);
return;
}
// Some boneheaded Apple engineers decided to reverse kVK_ANSI_Grave and kVK_ISO_Section on the 105-key layouts...
if(!HAS_ANY_FEATURE(kb, FEAT_LMASK)){
// If the layout hasn't been set yet, it can be auto-detected from certain keys
if(scancode == KEY_BACKSLASH_ISO || scancode == KEY_102ND)
kb->features |= FEAT_ISO;
else if(scancode == KEY_BACKSLASH)
kb->features |= FEAT_ANSI;
}
if(scancode == KEY_BACKSLASH_ISO)
scancode = KEY_BACKSLASH;
if(HAS_FEATURES(kb, FEAT_ISO)){
// Compensate for key reversal
if(scancode == KEY_GRAVE)
scancode = KEY_102ND;
else if(scancode == KEY_102ND)
scancode = KEY_GRAVE;
}
// Check for modifier keys and update flags
int isMod = 0;
IOOptionBits mod = 0;
if(scancode == KEY_CAPSLOCK){
if(down)
kb->modifiers ^= NX_ALPHASHIFTMASK;
isMod = 1;
// Detach a thread to update the indicator state
if(!kb->indicthread){
// The thread is only spawned if kb->indicthread is null.
// Due to the logic inside the thread, this means that it could theoretically be spawned twice, but never a third time.
// Moreover, if it is spawned more than once, the indicator state will remain correct due to dmutex staying locked.
if(!pthread_create(&kb->indicthread, 0, indicator_update, kb))
pthread_detach(kb->indicthread);
}
}
else if(scancode == KEY_LEFTSHIFT) mod = NX_DEVICELSHIFTKEYMASK;
else if(scancode == KEY_RIGHTSHIFT) mod = NX_DEVICERSHIFTKEYMASK;
else if(scancode == KEY_LEFTCTRL) mod = NX_DEVICELCTLKEYMASK;
else if(scancode == KEY_RIGHTCTRL) mod = NX_DEVICERCTLKEYMASK;
else if(scancode == KEY_LEFTMETA) mod = NX_DEVICELCMDKEYMASK;
else if(scancode == KEY_RIGHTMETA) mod = NX_DEVICERCMDKEYMASK;
else if(scancode == KEY_LEFTALT) mod = NX_DEVICELALTKEYMASK;
else if(scancode == KEY_RIGHTALT) mod = NX_DEVICERALTKEYMASK;
else if(scancode == KEY_FN) mod = NX_SECONDARYFNMASK;
if(mod){
// Update global modifiers
if(down)
mod |= kb->modifiers;
else
mod = kb->modifiers & ~mod;
if((mod & NX_DEVICELSHIFTKEYMASK) || (mod & NX_DEVICERSHIFTKEYMASK)) mod |= NX_SHIFTMASK; else mod &= ~NX_SHIFTMASK;
if((mod & NX_DEVICELCTLKEYMASK) || (mod & NX_DEVICERCTLKEYMASK)) mod |= NX_CONTROLMASK; else mod &= ~NX_CONTROLMASK;
if((mod & NX_DEVICELCMDKEYMASK) || (mod & NX_DEVICERCMDKEYMASK)) mod |= NX_COMMANDMASK; else mod &= ~NX_COMMANDMASK;
if((mod & NX_DEVICELALTKEYMASK) || (mod & NX_DEVICERALTKEYMASK)) mod |= NX_ALTERNATEMASK; else mod &= ~NX_ALTERNATEMASK;
kb->modifiers = mod;
kb->lastkeypress = KEY_NONE;
isMod = 1;
} else if(!isMod){
// For any other key, trigger key repeat
if(down){
long repeat = repeattime(kb->event, 1);
if(repeat > 0){
kb->lastkeypress = scancode;
clock_gettime(CLOCK_MONOTONIC, &kb->keyrepeat);
timespec_add(&kb->keyrepeat, repeat);
} else
kb->lastkeypress = KEY_NONE;
} else
kb->lastkeypress = KEY_NONE;
}
ckb_info("scancode %x\n", scancode);
// Pick the appropriate add or remove function
add_remove_keys = down ? &add_to_keys : &remove_from_keys;
postevent_kp(kb->event, kb->modifiers, scancode, down, isMod, 0);
setkrtimer(kb);
if(IS_VENDOR(scancode)) { // Fn
scancode = scancode - KEY_CONSUMER;
(*add_remove_keys)(scancode, &(kbinput_vendor.keys));
ckb_info("Vendor\n %i", scancode);
IOConnectCallStructMethod(kb->event, post_keyboard_input_report, &kbinput_vendor, sizeof(kbinput_vendor), NULL, 0);
} else if(IS_CONSUMER(scancode)){
scancode = scancode - KEY_CONSUMER;
(*add_remove_keys)(scancode, &(kbinput_consumer.keys));
IOConnectCallStructMethod(kb->event, post_keyboard_input_report, &kbinput_consumer, sizeof(kbinput_consumer), NULL, 0);
} else {
(*add_remove_keys)(scancode, &(kbinput_key.keys));
IOConnectCallStructMethod(kb->event, post_keyboard_input_report, &kbinput_key, sizeof(kbinput_key), NULL, 0);
}
}
void os_mousemove(usbdevice* kb, int x, int y){
postevent_mm(kb->event, x, y, HAS_FEATURES(kb, FEAT_MOUSEACCEL), kb->mousestate);
mouseinput.x = x;
mouseinput.y = y;
IOConnectCallStructMethod(kb->event_mouse, post_pointing_input_report, &mouseinput, sizeof(mouseinput), NULL, 0);
}
int os_setupindicators(usbdevice* kb){
@@ -431,3 +152,4 @@ int os_setupindicators(usbdevice* kb){
}
#endif
#endif
+433
View File
@@ -0,0 +1,433 @@
#include "command.h"
#include "device.h"
#include "input.h"
#ifdef OS_MAC
#include <errno.h>
#include <sys/sysctl.h>
int osx_ver = -1;
// Numpad keys have an extra flag
#define IS_NUMPAD(scancode) ((scancode) >= kVK_ANSI_KeypadDecimal && (scancode) <= kVK_ANSI_Keypad9 && (scancode) != kVK_ANSI_KeypadClear && (scancode) != kVK_ANSI_KeypadEnter)
pthread_mutex_t _euid_guard = PTHREAD_MUTEX_INITIALIZER;
// Event helpers
static void postevent(io_connect_t event, UInt32 type, NXEventData* ev, IOOptionBits flags, IOOptionBits options, int silence_errors){
// Hack #1: IOHIDPostEvent will fail with kIOReturnNotPrivileged if the event doesn't originate from the UID that owns /dev/console
// You'd think being root would be good enough. You'd be wrong. ckb-daemon needs to run as root for other reasons though
// (namely, being able to seize the physical IOHIDDevices) so what we do instead is change our EUID to the appropriate owner,
// post the event, and then change it right back.
// Yeah...
uid_t uid = 0;
gid_t gid = 0;
struct stat file;
if(!stat("/dev/console", &file)){
uid = file.st_uid;
gid = file.st_gid;
}
IOGPoint location = {0, 0};
// Sierra or higher doesn't need this
if(osx_ver < 16){
if((options & kIOHIDSetRelativeCursorPosition) && type != NX_MOUSEMOVED){
// Hack #2: IOHIDPostEvent will not accept relative mouse coordinates for any event other than NX_MOUSEMOVED
// So we need to get the current absolute coordinates from CoreGraphics and then modify those...
// No longer required in macOS >= 10.12
CGEventRef cge = CGEventCreate(nil);
CGPoint loc = CGEventGetLocation(cge);
CFRelease(cge);
location.x = floor(loc.x + ev->mouseMove.dx);
location.y = floor(loc.y + ev->mouseMove.dy);
options = (options & ~kIOHIDSetRelativeCursorPosition) | kIOHIDSetCursorPosition;
}
}
euid_guard_start;
if(uid != 0)
seteuid(uid);
if(gid != 0)
setegid(gid);
kern_return_t res = IOHIDPostEvent(event, type, location, ev, kNXEventDataVersion, flags | NX_NONCOALSESCEDMASK, options);
if(res != kIOReturnSuccess && !silence_errors)
ckb_warn("Post event failed: %x\n", res);
if(uid != 0)
seteuid(0);
if(gid != 0)
setegid(0);
euid_guard_stop;
}
// Keypress
#define aux_key_data(scancode, down, is_repeat) ((scancode) << 16 | ((down) ? 0x0a00 : 0x0b00) | !!(is_repeat))
static void postevent_kp(io_connect_t event, int kbflags, int scancode, int down, int is_flags, int is_repeat){
NXEventData kp;
memset(&kp, 0, sizeof(kp));
UInt32 type;
IOOptionBits flags = kbflags;
IOOptionBits options = 0;
if(scancode == KEY_CAPSLOCK){
// Caps lock emits NX_FLAGSCHANGED when pressed, but also NX_SYSDEFINED on both press and release
kp.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
kp.compound.misc.L[0] = aux_key_data(NX_KEYTYPE_CAPS_LOCK, down, is_repeat);
postevent(event, NX_SYSDEFINED, &kp, flags, options, 1);
if(!down)
return;
memset(&kp, 0, sizeof(kp));
}
if(IS_MEDIA(scancode)){
kp.compound.subType = (scancode != KEY_POWER ? NX_SUBTYPE_AUX_CONTROL_BUTTONS : NX_SUBTYPE_POWER_KEY);
kp.compound.misc.L[0] = aux_key_data(scancode - KEY_MEDIA, down, is_repeat);
type = NX_SYSDEFINED;
} else {
if(is_flags){
// Modifier (shift, ctrl, etc)
type = NX_FLAGSCHANGED;
options = kIOHIDSetGlobalEventFlags;
} else
// Standard key
type = down ? NX_KEYDOWN : NX_KEYUP;
kp.key.repeat = is_repeat;
kp.key.keyCode = scancode;
kp.key.origCharSet = kp.key.charSet = NX_ASCIISET;
if(IS_NUMPAD(scancode))
flags |= NX_NUMERICPADMASK;
else if(scancode == kVK_Help)
flags |= NX_HELPMASK;
}
postevent(event, type, &kp, flags, options, !down || is_repeat);
// Don't print errors on key up or key repeat ^
}
// Mouse button
static void postevent_mb(io_connect_t event, int button, int down){
NXEventData mb;
memset(&mb, 0, sizeof(mb));
mb.compound.subType = NX_SUBTYPE_AUX_MOUSE_BUTTONS;
mb.compound.misc.L[0] = (1 << button);
mb.compound.misc.L[1] = down ? (1 << button) : 0;
postevent(event, NX_SYSDEFINED, &mb, 0, 0, !down);
// Mouse presses actually generate two events, one with a bitfield of buttons, one with a button number
memset(&mb, 0, sizeof(mb));
UInt32 type;
mb.mouse.buttonNumber = button;
switch(button){
case 0:
type = down ? NX_LMOUSEDOWN : NX_LMOUSEUP;
break;
case 1:
type = down ? NX_RMOUSEDOWN : NX_RMOUSEUP;
break;
default:
type = down ? NX_OMOUSEDOWN : NX_OMOUSEUP;
}
if(down)
mb.mouse.pressure = 255;
postevent(event, type, &mb, 0, 0, 1);
}
// input_mac_mouse.c
extern void wheel_accel(io_connect_t event, int* deltaAxis1, SInt32* fixedDeltaAxis1, SInt32* pointDeltaAxis1);
extern void mouse_accel(io_connect_t event, int* x, int* y);
// Mouse wheel
static void postevent_wheel(io_connect_t event, int scroll_rate, int value){
NXEventData mm;
memset(&mm, 0, sizeof(mm));
if(scroll_rate == SCROLL_ACCELERATED){
wheel_accel(event, &value, &mm.scrollWheel.fixedDeltaAxis1, &mm.scrollWheel.pointDeltaAxis1);
mm.scrollWheel.deltaAxis1 = value;
} else {
// If acceleration is disabled, use a fixed delta
mm.scrollWheel.deltaAxis1 = value * scroll_rate;
}
postevent(event, NX_SCROLLWHEELMOVED, &mm, 0, 0, 0);
}
// Mouse axis
static void postevent_mm(io_connect_t event, int x, int y, int use_accel, uchar buttons){
NXEventData mm;
memset(&mm, 0, sizeof(mm));
UInt32 type = NX_MOUSEMOVED;
if(use_accel)
mouse_accel(event, &x, &y);
mm.mouseMove.dx = x;
mm.mouseMove.dy = y;
if(buttons != 0){
// If a button is pressed, the event type changes
if(buttons & 1)
type = NX_LMOUSEDRAGGED;
else if(buttons & 2)
type = NX_RMOUSEDRAGGED;
else
type = NX_OMOUSEDRAGGED;
// Pick the button index based on the lowest-numbered button
int button = 0;
while(!(buttons & 1)){
button++;
buttons >>= 1;
}
mm.mouse.pressure = 255;
mm.mouse.buttonNumber = button;
}
postevent(event, type, &mm, 0, kIOHIDSetRelativeCursorPosition, 1);
}
// Key repeat delay helper (result in ns)
long repeattime(io_connect_t event, int first){
long delay = 0;
CFTypeRef cf;
kern_return_t param = IOHIDCopyCFTypeParameter(event, (first ? CFSTR(kIOHIDInitialKeyRepeatKey) : CFSTR(kIOHIDKeyRepeatKey)), &cf);
if(param != KERN_SUCCESS)
return -1;
if(!CFNumberGetValue(cf, kCFNumberLongType, &delay))
return -1;
return delay;
}
// Send keyup events for every scancode in the keymap
void clearkeys(usbdevice* kb){
for(int key = 0; key < N_KEYS_INPUT; key++){
int scan = kb->keymap[key].scan;
if((scan & SCAN_SILENT) || scan == BTN_WHEELUP || scan == BTN_WHEELDOWN || IS_MEDIA(scan))
continue;
postevent_kp(kb->event, 0, scan, 0, 0, 0);
}
}
// Opens HID service. Returns kIOReturnSuccess on success.
static int open_iohid(io_connect_t* connection){
char osx_version_buf[256];
size_t size = sizeof(osx_version_buf);
sysctlbyname("kern.osrelease", osx_version_buf, &size, NULL, 0);
char osx_version[3];
strncpy(osx_version, osx_version_buf, 2);
osx_ver = atoi(osx_version);
io_iterator_t iter;
io_service_t service;
// Open master port (if not done yet)
static mach_port_t master = 0;
kern_return_t res;
if(!master && (res = IOMasterPort(bootstrap_port, &master)) != kIOReturnSuccess){
master = 0;
ckb_err("Unable to open master port: 0x%08x\n", res);
goto failure;
}
// Open the HID service
if((res = IOServiceGetMatchingServices(master, IOServiceMatching(kIOHIDSystemClass), &iter)) != kIOReturnSuccess)
goto failure;
service = IOIteratorNext(iter);
if(!service){
res = kIOReturnNotOpen;
goto failure_release_iter;
}
if((res = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, connection)) != kIOReturnSuccess){
*connection = 0;
goto failure_release_iter;
}
// Finished; release objects and return success
IOObjectRelease(service);
failure_release_iter:
IOObjectRelease(iter);
failure:
return res;
}
int os_inputopen(usbdevice* kb){
// The IO service isn't always ready at startup, so if it's not, wait until it is
IOReturn res;
while((res = open_iohid(&kb->event)) != kIOReturnSuccess){
if(res != kIOReturnNotOpen){
// If this is a more serious error, at least print a warning
ckb_err("Unable to open HID system: 0x%08x\n", res);
sleep(1);
continue;
}
clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec) {.tv_nsec = 10000000}, NULL);
}
clearkeys(kb);
return 0;
}
void os_inputclose(usbdevice* kb){
if(kb->event){
clearkeys(kb);
IOServiceClose(kb->event);
kb->event = 0;
}
}
// Starts/stops key-repeat timer as appropriate
static void setkrtimer(usbdevice* kb){
if(kb->lastkeypress == KEY_NONE)
CFRunLoopRemoveTimer(kb->input_loop, kb->krtimer, kCFRunLoopCommonModes);
else
CFRunLoopAddTimer(kb->input_loop, kb->krtimer, kCFRunLoopCommonModes);
}
// Retrigger the last-pressed key
static void _keyretrigger(usbdevice* kb){
int scancode = kb->lastkeypress;
postevent_kp(kb->event, kb->modifiers, scancode, 1, 0, 1);
// Set next key repeat time
long repeat = repeattime(kb->event, 0);
if(repeat > 0)
timespec_add(&kb->keyrepeat, repeat);
else
kb->lastkeypress = KEY_NONE;
}
void keyretrigger(CFRunLoopTimerRef timer, void* info){
usbdevice* kb = info;
// Repeat the key as many times as needed to catch up
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
while(!(kb->lastkeypress & (SCAN_SILENT | SCAN_MOUSE)) && timespec_ge(time, kb->keyrepeat))
_keyretrigger(kb);
setkrtimer(kb);
}
// Unlike Linux, OSX keyboards have independent caps lock states. This means they're set by the driver itself so we don't poll for external events.
// However, updating indicator state requires locking dmutex and we never want to do that in the input thread.
// Instead, we launch a single-shot thread to update the state.
static void* indicator_update(void* context){
usbdevice* kb = context;
pthread_mutex_lock(dmutex(kb));
{
pthread_mutex_lock(imutex(kb));
IOOptionBits modifiers = kb->modifiers;
// Allow the thread to be spawned again
kb->indicthread = 0;
pthread_mutex_unlock(imutex(kb));
// Num lock on, Caps dependent on modifier state
uchar ileds = 1 | !!(modifiers & NX_ALPHASHIFTMASK) << 1;
kb->hw_ileds = ileds;
kb->vtable->updateindicators(kb, 0);
}
pthread_mutex_unlock(dmutex(kb));
return 0;
}
void os_keypress(usbdevice* kb, int scancode, int down){
// Trigger any pending repeats first
keyretrigger(NULL, kb);
// Key/button pressed
if(scancode & SCAN_MOUSE){
if(scancode == BTN_WHEELUP){
if(down)
postevent_wheel(kb->event, kb->scroll_rate, 1);
return;
} else if(scancode == BTN_WHEELDOWN){
if(down)
postevent_wheel(kb->event, kb->scroll_rate, -1);
return;
}
int button = scancode & ~SCAN_MOUSE;
// Reverse or collapse left/right buttons if the system preferences say so
int mode;
if(IOHIDGetMouseButtonMode(kb->event, &mode) == kIOReturnSuccess){
if(mode == kIOHIDButtonMode_ReverseLeftRightClicks && button == 0)
button = 1;
else if(mode != kIOHIDButtonMode_EnableRightClick && button == 1)
button = 0;
}
postevent_mb(kb->event, button, down);
if(down)
kb->mousestate |= (1 << button);
else
kb->mousestate &= ~(1 << button);
return;
}
// Some boneheaded Apple engineers decided to reverse kVK_ANSI_Grave and kVK_ISO_Section on the 105-key layouts...
if(!HAS_ANY_FEATURE(kb, FEAT_LMASK)){
// If the layout hasn't been set yet, it can be auto-detected from certain keys
if(scancode == KEY_BACKSLASH_ISO || scancode == KEY_102ND)
kb->features |= FEAT_ISO;
else if(scancode == KEY_BACKSLASH)
kb->features |= FEAT_ANSI;
}
if(scancode == KEY_BACKSLASH_ISO)
scancode = KEY_BACKSLASH;
if(HAS_FEATURES(kb, FEAT_ISO)){
// Compensate for key reversal
if(scancode == KEY_GRAVE)
scancode = KEY_102ND;
else if(scancode == KEY_102ND)
scancode = KEY_GRAVE;
}
// Check for modifier keys and update flags
int isMod = 0;
IOOptionBits mod = 0;
if(scancode == KEY_CAPSLOCK){
if(down)
kb->modifiers ^= NX_ALPHASHIFTMASK;
isMod = 1;
// Detach a thread to update the indicator state
if(!kb->indicthread){
// The thread is only spawned if kb->indicthread is null.
// Due to the logic inside the thread, this means that it could theoretically be spawned twice, but never a third time.
// Moreover, if it is spawned more than once, the indicator state will remain correct due to dmutex staying locked.
if(!pthread_create(&kb->indicthread, 0, indicator_update, kb))
pthread_detach(kb->indicthread);
}
}
else if(scancode == KEY_LEFTSHIFT) mod = NX_DEVICELSHIFTKEYMASK;
else if(scancode == KEY_RIGHTSHIFT) mod = NX_DEVICERSHIFTKEYMASK;
else if(scancode == KEY_LEFTCTRL) mod = NX_DEVICELCTLKEYMASK;
else if(scancode == KEY_RIGHTCTRL) mod = NX_DEVICERCTLKEYMASK;
else if(scancode == KEY_LEFTMETA) mod = NX_DEVICELCMDKEYMASK;
else if(scancode == KEY_RIGHTMETA) mod = NX_DEVICERCMDKEYMASK;
else if(scancode == KEY_LEFTALT) mod = NX_DEVICELALTKEYMASK;
else if(scancode == KEY_RIGHTALT) mod = NX_DEVICERALTKEYMASK;
else if(scancode == KEY_FN) mod = NX_SECONDARYFNMASK;
if(mod){
// Update global modifiers
if(down)
mod |= kb->modifiers;
else
mod = kb->modifiers & ~mod;
if((mod & NX_DEVICELSHIFTKEYMASK) || (mod & NX_DEVICERSHIFTKEYMASK)) mod |= NX_SHIFTMASK; else mod &= ~NX_SHIFTMASK;
if((mod & NX_DEVICELCTLKEYMASK) || (mod & NX_DEVICERCTLKEYMASK)) mod |= NX_CONTROLMASK; else mod &= ~NX_CONTROLMASK;
if((mod & NX_DEVICELCMDKEYMASK) || (mod & NX_DEVICERCMDKEYMASK)) mod |= NX_COMMANDMASK; else mod &= ~NX_COMMANDMASK;
if((mod & NX_DEVICELALTKEYMASK) || (mod & NX_DEVICERALTKEYMASK)) mod |= NX_ALTERNATEMASK; else mod &= ~NX_ALTERNATEMASK;
kb->modifiers = mod;
kb->lastkeypress = KEY_NONE;
isMod = 1;
} else if(!isMod){
// For any other key, trigger key repeat
if(down){
long repeat = repeattime(kb->event, 1);
if(repeat > 0){
kb->lastkeypress = scancode;
clock_gettime(CLOCK_MONOTONIC, &kb->keyrepeat);
timespec_add(&kb->keyrepeat, repeat);
} else
kb->lastkeypress = KEY_NONE;
} else
kb->lastkeypress = KEY_NONE;
}
postevent_kp(kb->event, kb->modifiers, scancode, down, isMod, 0);
setkrtimer(kb);
}
void os_mousemove(usbdevice* kb, int x, int y){
postevent_mm(kb->event, x, y, HAS_FEATURES(kb, FEAT_MOUSEACCEL), kb->mousestate);
}
int os_setupindicators(usbdevice* kb){
// Set NumLock on permanently
kb->hw_ileds = kb->hw_ileds_old = kb->ileds = 1;
return 0;
}
#endif
@@ -1,6 +1,6 @@
#include "includes.h"
#ifdef OS_MAC
#ifdef OS_MAC_LEGACY
// Most of this code shamelessly stolen from:
// http://www.opensource.apple.com/source/IOHIDFamily/IOHIDFamily-606.1.7/IOHIDSystem/IOHIPointing.cpp
@@ -1438,4 +1438,4 @@ void wheel_accel(io_connect_t event, int* deltaAxis1, SInt32* fixedDeltaAxis1, S
pthread_mutex_unlock(&mutex);
}
#endif // OS_MAC
#endif // OS_MAC_LEGACY
+114
View File
@@ -0,0 +1,114 @@
#ifndef OS_MAC_LEGACY
// Based on https://github.com/tekezo/Karabiner-Elements/blob/master/src/vendor/Karabiner-VirtualHIDDevice/dist/include/karabiner_virtual_hid_device.hpp
#define VIRTUAL_HID_ROOT_NAME "org_pqrs_driver_Karabiner_VirtualHIDDevice_VirtualHIDRoot_v060800"
// Kext constant. Don't modify unless you're absolutely sure you know what you're doing.
#define VHID_KEYS_LEN 32
enum user_client_method {
// VirtualHIDKeyboard
initialize_virtual_hid_keyboard,
terminate_virtual_hid_keyboard,
is_virtual_hid_keyboard_ready,
post_keyboard_input_report,
post_consumer_input_report,
post_apple_vendor_top_case_input_report,
post_apple_vendor_keyboard_input_report,
reset_virtual_hid_keyboard,
// VirtualHIDPointing
initialize_virtual_hid_pointing,
terminate_virtual_hid_pointing,
post_pointing_input_report,
reset_virtual_hid_pointing,
end_,
};
enum modifier {
left_control = 0x1 << 0,
left_shift = 0x1 << 1,
left_option = 0x1 << 2,
left_command = 0x1 << 3,
right_control = 0x1 << 4,
right_shift = 0x1 << 5,
right_option = 0x1 << 6,
right_command = 0x1 << 7,
};
// VirtualHIDKeyboard
typedef struct keyboard_initialization {
uint8_t country_code;
} vhid_properties;
typedef struct keys {
uint8_t keys_[VHID_KEYS_LEN];
} vhid_keys;
typedef struct modifiers {
uint8_t modifiers_;
} vhid_modifiers;
typedef struct keyboard_input {
uint8_t report_id_;
vhid_modifiers modifiers;
uint8_t reserved;
vhid_keys keys;
} vhid_kbinput;
/*typedef struct consumer_input {
uint8_t report_id_;
vhid_keys keys;
} vhid_kbconsumerinput;
typedef struct avtopcase_input {
uint8_t report_id_;
vhid_keys keys;
} vhid_kbavtopcaseinput;*/
// Functions to add/remove keys from report
void add_to_keys(int scan, vhid_keys* input){
for(int i = 0; i < VHID_KEYS_LEN; i++){
if(input->keys_[i] == 0){
input->keys_[i] = scan;
return;
}
}
ckb_warn("Dropping excess keypress\n");
}
void remove_from_keys(int scan, vhid_keys* input){
for(int i = 0; i < VHID_KEYS_LEN; i++){
if(input->keys_[i] == scan){
input->keys_[i] = 0;
return;
}
}
ckb_warn("Couldn't find key to release\n");
}
// VirtualHIDPointing
typedef struct buttons {
uint32_t buttons_;
} vhid_buttons;
typedef struct pointing_input {
vhid_buttons buttons;
uint8_t x;
uint8_t y;
uint8_t vertical_wheel;
uint8_t horizontal_wheel;
} vhid_mouseinput;
// Functions to add/remove buttons from report
void add_to_buttons(int scan, vhid_mouseinput* input){
input->buttons.buttons_ |= (0x1 << (scan - 1));
}
void remove_from_buttons(int scan, vhid_mouseinput* input){
input->buttons.buttons_ &= ~(0x1 << (scan - 1));
}
void (*add_remove_keys)(int scan, vhid_keys* input);
#endif
+149 -139
View File
@@ -4,163 +4,173 @@
#include "os.h"
#ifdef OS_MAC
// Emulate Linux key constants for OSX
#ifdef OS_MAC_LEGACY
#define KEY_ESC kVK_Escape
#define KEY_F1 kVK_F1
#define KEY_F2 kVK_F2
#define KEY_F3 kVK_F3
#define KEY_F4 kVK_F4
#define KEY_F5 kVK_F5
#define KEY_F6 kVK_F6
#define KEY_F7 kVK_F7
#define KEY_F8 kVK_F8
#define KEY_F9 kVK_F9
#define KEY_F10 kVK_F10
#define KEY_F11 kVK_F11
#define KEY_F12 kVK_F12
#define KEY_F13 kVK_F13
#define KEY_F14 kVK_F14
#define KEY_F15 kVK_F15
#define KEY_F16 kVK_F16
#define KEY_F17 kVK_F17
#define KEY_F18 kVK_F18
#define KEY_F19 kVK_F19
#define KEY_F20 kVK_F20
#define KEY_F21 -1
#define KEY_F22 -1
#define KEY_F23 -1
#define KEY_F24 -1
#include "keymap_mac_legacy.h"
#define KEY_1 kVK_ANSI_1
#define KEY_2 kVK_ANSI_2
#define KEY_3 kVK_ANSI_3
#define KEY_4 kVK_ANSI_4
#define KEY_5 kVK_ANSI_5
#define KEY_6 kVK_ANSI_6
#define KEY_7 kVK_ANSI_7
#define KEY_8 kVK_ANSI_8
#define KEY_9 kVK_ANSI_9
#define KEY_0 kVK_ANSI_0
#else
#define KEY_A kVK_ANSI_A
#define KEY_B kVK_ANSI_B
#define KEY_C kVK_ANSI_C
#define KEY_D kVK_ANSI_D
#define KEY_E kVK_ANSI_E
#define KEY_F kVK_ANSI_F
#define KEY_G kVK_ANSI_G
#define KEY_H kVK_ANSI_H
#define KEY_I kVK_ANSI_I
#define KEY_J kVK_ANSI_J
#define KEY_K kVK_ANSI_K
#define KEY_L kVK_ANSI_L
#define KEY_M kVK_ANSI_M
#define KEY_N kVK_ANSI_N
#define KEY_O kVK_ANSI_O
#define KEY_P kVK_ANSI_P
#define KEY_Q kVK_ANSI_Q
#define KEY_R kVK_ANSI_R
#define KEY_S kVK_ANSI_S
#define KEY_T kVK_ANSI_T
#define KEY_U kVK_ANSI_U
#define KEY_V kVK_ANSI_V
#define KEY_W kVK_ANSI_W
#define KEY_X kVK_ANSI_X
#define KEY_Y kVK_ANSI_Y
#define KEY_Z kVK_ANSI_Z
// Replace Linux key constants with HID scancodes for macOS w/VirtualHIDDevice
#define KEY_GRAVE kVK_ANSI_Grave
#define KEY_102ND kVK_ISO_Section
#define KEY_MINUS kVK_ANSI_Minus
#define KEY_EQUAL kVK_ANSI_Equal
#define KEY_BACKSPACE kVK_Delete
#define KEY_LEFTBRACE kVK_ANSI_LeftBracket
#define KEY_RIGHTBRACE kVK_ANSI_RightBracket
#define KEY_BACKSLASH kVK_ANSI_Backslash
#define KEY_SEMICOLON kVK_ANSI_Semicolon
#define KEY_APOSTROPHE kVK_ANSI_Quote
#define KEY_ENTER kVK_Return
#define KEY_COMMA kVK_ANSI_Comma
#define KEY_DOT kVK_ANSI_Period
#define KEY_SLASH kVK_ANSI_Slash
#define KEY_SPACE kVK_Space
#define KEY_ESC kHIDUsage_KeyboardEscape
#define KEY_F1 kHIDUsage_KeyboardF1
#define KEY_F2 kHIDUsage_KeyboardF2
#define KEY_F3 kHIDUsage_KeyboardF3
#define KEY_F4 kHIDUsage_KeyboardF4
#define KEY_F5 kHIDUsage_KeyboardF5
#define KEY_F6 kHIDUsage_KeyboardF6
#define KEY_F7 kHIDUsage_KeyboardF7
#define KEY_F8 kHIDUsage_KeyboardF8
#define KEY_F9 kHIDUsage_KeyboardF9
#define KEY_F10 kHIDUsage_KeyboardF10
#define KEY_F11 kHIDUsage_KeyboardF11
#define KEY_F12 kHIDUsage_KeyboardF12
#define KEY_F13 kHIDUsage_KeyboardF13
#define KEY_F14 kHIDUsage_KeyboardF14
#define KEY_F15 kHIDUsage_KeyboardF15
#define KEY_F16 kHIDUsage_KeyboardF16
#define KEY_F17 kHIDUsage_KeyboardF17
#define KEY_F18 kHIDUsage_KeyboardF18
#define KEY_F19 kHIDUsage_KeyboardF19
#define KEY_F20 kHIDUsage_KeyboardF20
#define KEY_F21 kHIDUsage_KeyboardF21
#define KEY_F22 kHIDUsage_KeyboardF22
#define KEY_F23 kHIDUsage_KeyboardF23
#define KEY_F24 kHIDUsage_KeyboardF24
#define KEY_TAB kVK_Tab
#define KEY_CAPSLOCK kVK_CapsLock
#define KEY_LEFTSHIFT kVK_Shift
#define KEY_RIGHTSHIFT kVK_RightShift
#define KEY_LEFTCTRL kVK_Control
#define KEY_RIGHTCTRL kVK_RightControl
#define KEY_LEFTMETA kVK_Command
#define KEY_RIGHTMETA (kVK_Command - 1) // This isn't listed as kVK_RightCommand for some reason?
#define KEY_LEFTALT kVK_Option
#define KEY_RIGHTALT kVK_RightOption
#define KEY_1 kHIDUsage_Keyboard1
#define KEY_2 kHIDUsage_Keyboard2
#define KEY_3 kHIDUsage_Keyboard3
#define KEY_4 kHIDUsage_Keyboard4
#define KEY_5 kHIDUsage_Keyboard5
#define KEY_6 kHIDUsage_Keyboard6
#define KEY_7 kHIDUsage_Keyboard7
#define KEY_8 kHIDUsage_Keyboard8
#define KEY_9 kHIDUsage_Keyboard9
#define KEY_0 kHIDUsage_Keyboard0
#define KEY_A kHIDUsage_KeyboardA
#define KEY_B kHIDUsage_KeyboardB
#define KEY_C kHIDUsage_KeyboardC
#define KEY_D kHIDUsage_KeyboardD
#define KEY_E kHIDUsage_KeyboardE
#define KEY_F kHIDUsage_KeyboardF
#define KEY_G kHIDUsage_KeyboardG
#define KEY_H kHIDUsage_KeyboardH
#define KEY_I kHIDUsage_KeyboardI
#define KEY_J kHIDUsage_KeyboardJ
#define KEY_K kHIDUsage_KeyboardK
#define KEY_L kHIDUsage_KeyboardL
#define KEY_M kHIDUsage_KeyboardM
#define KEY_N kHIDUsage_KeyboardN
#define KEY_O kHIDUsage_KeyboardO
#define KEY_P kHIDUsage_KeyboardP
#define KEY_Q kHIDUsage_KeyboardQ
#define KEY_R kHIDUsage_KeyboardR
#define KEY_S kHIDUsage_KeyboardS
#define KEY_T kHIDUsage_KeyboardT
#define KEY_U kHIDUsage_KeyboardU
#define KEY_V kHIDUsage_KeyboardV
#define KEY_W kHIDUsage_KeyboardW
#define KEY_X kHIDUsage_KeyboardX
#define KEY_Y kHIDUsage_KeyboardY
#define KEY_Z kHIDUsage_KeyboardZ
#define KEY_GRAVE kHIDUsage_KeyboardGraveAccentAndTilde
#define KEY_102ND kHIDUsage_KeyboardNonUSBackslash
#define KEY_MINUS kHIDUsage_KeyboardHyphen
#define KEY_EQUAL kHIDUsage_KeyboardEqualSign
#define KEY_BACKSPACE kHIDUsage_KeyboardDeleteOrBackspace
#define KEY_LEFTBRACE kHIDUsage_KeyboardOpenBracket
#define KEY_RIGHTBRACE kHIDUsage_KeyboardCloseBracket
#define KEY_BACKSLASH kHIDUsage_KeyboardBackslash
#define KEY_SEMICOLON kHIDUsage_KeyboardSemicolon
#define KEY_APOSTROPHE kHIDUsage_KeyboardQuote
#define KEY_ENTER kHIDUsage_KeyboardReturnOrEnter
#define KEY_COMMA kHIDUsage_KeyboardComma
#define KEY_DOT kHIDUsage_KeyboardPeriod
#define KEY_SLASH kHIDUsage_KeyboardSlash
#define KEY_SPACE kHIDUsage_KeyboardSpacebar
#define KEY_TAB kHIDUsage_KeyboardTab
#define KEY_CAPSLOCK kHIDUsage_KeyboardCapsLock
#define KEY_LEFTSHIFT kHIDUsage_KeyboardLeftShift
#define KEY_RIGHTSHIFT kHIDUsage_KeyboardRightShift
#define KEY_LEFTCTRL kHIDUsage_KeyboardLeftControl
#define KEY_RIGHTCTRL kHIDUsage_KeyboardRightControl
#define KEY_LEFTMETA kHIDUsage_KeyboardLeftGUI
#define KEY_RIGHTMETA kHIDUsage_KeyboardRightGUI // This isn't listed as kVK_RightCommand for some reason?
#define KEY_LEFTALT kHIDUsage_KeyboardLeftAlt
#define KEY_RIGHTALT kHIDUsage_KeyboardRightAlt
#define KEY_COMPOSE -1 // OSX has no context menu key
#define KEY_FN kVK_Function
#define KEY_FN 0x03 //kHIDUsage_AV_TopCase_KeyboardFn
#define KEY_SYSRQ kVK_F13
#define KEY_SCROLLLOCK kVK_F14
#define KEY_PAUSE kVK_F15
#define KEY_INSERT kVK_Help
#define KEY_HOME kVK_Home
#define KEY_PAGEUP kVK_PageUp
#define KEY_DELETE kVK_ForwardDelete
#define KEY_END kVK_End
#define KEY_PAGEDOWN kVK_PageDown
#define KEY_SYSRQ kHIDUsage_KeyboardF13
#define KEY_SCROLLLOCK kHIDUsage_KeyboardF14
#define KEY_PAUSE kHIDUsage_KeyboardF15
#define KEY_INSERT kHIDUsage_KeyboardInsert
#define KEY_HOME kHIDUsage_KeyboardHome
#define KEY_PAGEUP kHIDUsage_KeyboardPageUp
#define KEY_DELETE kHIDUsage_KeyboardDeleteForward
#define KEY_END kHIDUsage_KeyboardEnd
#define KEY_PAGEDOWN kHIDUsage_KeyboardPageDown
#define KEY_UP kVK_UpArrow
#define KEY_LEFT kVK_LeftArrow
#define KEY_DOWN kVK_DownArrow
#define KEY_RIGHT kVK_RightArrow
#define KEY_UP kHIDUsage_KeyboardUpArrow
#define KEY_LEFT kHIDUsage_KeyboardLeftArrow
#define KEY_DOWN kHIDUsage_KeyboardDownArrow
#define KEY_RIGHT kHIDUsage_KeyboardRightArrow
#define KEY_NUMLOCK kVK_ANSI_KeypadClear
#define KEY_KPSLASH kVK_ANSI_KeypadDivide
#define KEY_KPASTERISK kVK_ANSI_KeypadMultiply
#define KEY_KPMINUS kVK_ANSI_KeypadMinus
#define KEY_KPPLUS kVK_ANSI_KeypadPlus
#define KEY_KPENTER kVK_ANSI_KeypadEnter
#define KEY_KPDOT kVK_ANSI_KeypadDecimal
#define KEY_KP1 kVK_ANSI_Keypad1
#define KEY_KP2 kVK_ANSI_Keypad2
#define KEY_KP3 kVK_ANSI_Keypad3
#define KEY_KP4 kVK_ANSI_Keypad4
#define KEY_KP5 kVK_ANSI_Keypad5
#define KEY_KP6 kVK_ANSI_Keypad6
#define KEY_KP7 kVK_ANSI_Keypad7
#define KEY_KP8 kVK_ANSI_Keypad8
#define KEY_KP9 kVK_ANSI_Keypad9
#define KEY_KP0 kVK_ANSI_Keypad0
#define KEY_NUMLOCK kHIDUsage_KeypadNumLock
#define KEY_KPSLASH kHIDUsage_KeypadSlash
#define KEY_KPASTERISK kHIDUsage_KeypadAsterisk
#define KEY_KPMINUS kHIDUsage_KeypadHyphen
#define KEY_KPPLUS kHIDUsage_KeypadPlus
#define KEY_KPENTER kHIDUsage_KeypadEnter
#define KEY_KPDOT kHIDUsage_KeypadPeriod
#define KEY_KP1 kHIDUsage_Keypad1
#define KEY_KP2 kHIDUsage_Keypad2
#define KEY_KP3 kHIDUsage_Keypad3
#define KEY_KP4 kHIDUsage_Keypad4
#define KEY_KP5 kHIDUsage_Keypad5
#define KEY_KP6 kHIDUsage_Keypad6
#define KEY_KP7 kHIDUsage_Keypad7
#define KEY_KP8 kHIDUsage_Keypad8
#define KEY_KP9 kHIDUsage_Keypad9
#define KEY_KP0 kHIDUsage_Keypad0
#define KEY_YEN kVK_JIS_Yen
#define KEY_RO kVK_JIS_Underscore
#define KEY_KATAKANAHIRAGANA kVK_JIS_Kana
#define KEY_HENKAN -1
#define KEY_MUHENKAN -1
#define KEY_YEN kHIDUsage_KeyboardInternational3
#define KEY_RO kHIDUsage_KeyboardInternational1
#define KEY_KATAKANAHIRAGANA kHIDUsage_KeyboardInternational2
#define KEY_HENKAN kHIDUsage_KeyboardInternational4
#define KEY_MUHENKAN kHIDUsage_KeyboardInternational5
#define KEY_MEDIA 0x800
#define IS_MEDIA(scancode) ((scancode) >= KEY_MEDIA)
#define KEY_MUTE (KEY_MEDIA + NX_KEYTYPE_MUTE)
#define KEY_VOLUMEUP (KEY_MEDIA + NX_KEYTYPE_SOUND_UP)
#define KEY_VOLUMEDOWN (KEY_MEDIA + NX_KEYTYPE_SOUND_DOWN)
#define KEY_STOPCD -1 // OSX has no stop key
#define KEY_PREVIOUSSONG (KEY_MEDIA + NX_KEYTYPE_PREVIOUS)
#define KEY_PLAYPAUSE (KEY_MEDIA + NX_KEYTYPE_PLAY)
#define KEY_NEXTSONG (KEY_MEDIA + NX_KEYTYPE_NEXT)
#define KEY_BRIGHTNESSUP (KEY_MEDIA + NX_KEYTYPE_BRIGHTNESS_UP)
#define KEY_BRIGHTNESSDOWN (KEY_MEDIA + NX_KEYTYPE_BRIGHTNESS_DOWN)
#define KEY_EJECTCD (KEY_MEDIA + NX_KEYTYPE_EJECT)
#define KEY_POWER (KEY_MEDIA + NX_POWER_KEY)
#define KEY_CONSUMER 0x800
#define IS_CONSUMER(scan) ((scan) >= KEY_CONSUMER)
#define KEY_MUTE (KEY_CONSUMER + kHIDUsage_Csmr_Mute)
#define KEY_VOLUMEUP (KEY_CONSUMER + kHIDUsage_Csmr_VolumeIncrement)
#define KEY_VOLUMEDOWN (KEY_CONSUMER + kHIDUsage_Csmr_VolumeDecrement)
#define KEY_STOPCD (KEY_CONSUMER + kHIDUsage_Csmr_Stop)
#define KEY_PREVIOUSSONG (KEY_CONSUMER + kHIDUsage_Csmr_ScanPreviousTrack)
#define KEY_PLAYPAUSE (KEY_CONSUMER + kHIDUsage_Csmr_PlayOrPause)
#define KEY_NEXTSONG (KEY_CONSUMER + kHIDUsage_Csmr_ScanNextTrack)
#define KEY_BRIGHTNESSUP (KEY_CONSUMER + 0x0020)
#define KEY_BRIGHTNESSDOWN (KEY_CONSUMER + 0x0021)
#define KEY_EJECTCD (KEY_CONSUMER + kHIDUsage_Csmr_Eject)
#define KEY_POWER (KEY_CONSUMER + 0x000c)
#define IS_VENDOR(scan) ((scan) >= KEY_CONSUMER && (scan) < KEY_CONSUMER + kHIDUsage_Csmr_ScanPreviousTrack)
#define BTN_LEFT 0
#define BTN_RIGHT 1
#define BTN_MIDDLE 2
#define BTN_LEFT 1
#define BTN_RIGHT 2
#define BTN_MIDDLE 3
#define BTN_SIDE 4
#define BTN_EXTRA 5
#define BTN_FORWARD 6
#define BTN_BACK 7
#define BTN_TASK 8
#endif //OS_MAC_LEGACY
#endif // OS_MAC
#endif // KEYMAP_MAC_H
+157
View File
@@ -0,0 +1,157 @@
// This should only be included when needed by keymap_mac.h
// Emulate Linux key constants for OSX
#define KEY_ESC kVK_Escape
#define KEY_F1 kVK_F1
#define KEY_F2 kVK_F2
#define KEY_F3 kVK_F3
#define KEY_F4 kVK_F4
#define KEY_F5 kVK_F5
#define KEY_F6 kVK_F6
#define KEY_F7 kVK_F7
#define KEY_F8 kVK_F8
#define KEY_F9 kVK_F9
#define KEY_F10 kVK_F10
#define KEY_F11 kVK_F11
#define KEY_F12 kVK_F12
#define KEY_F13 kVK_F13
#define KEY_F14 kVK_F14
#define KEY_F15 kVK_F15
#define KEY_F16 kVK_F16
#define KEY_F17 kVK_F17
#define KEY_F18 kVK_F18
#define KEY_F19 kVK_F19
#define KEY_F20 kVK_F20
#define KEY_F21 -1
#define KEY_F22 -1
#define KEY_F23 -1
#define KEY_F24 -1
#define KEY_1 kVK_ANSI_1
#define KEY_2 kVK_ANSI_2
#define KEY_3 kVK_ANSI_3
#define KEY_4 kVK_ANSI_4
#define KEY_5 kVK_ANSI_5
#define KEY_6 kVK_ANSI_6
#define KEY_7 kVK_ANSI_7
#define KEY_8 kVK_ANSI_8
#define KEY_9 kVK_ANSI_9
#define KEY_0 kVK_ANSI_0
#define KEY_A kVK_ANSI_A
#define KEY_B kVK_ANSI_B
#define KEY_C kVK_ANSI_C
#define KEY_D kVK_ANSI_D
#define KEY_E kVK_ANSI_E
#define KEY_F kVK_ANSI_F
#define KEY_G kVK_ANSI_G
#define KEY_H kVK_ANSI_H
#define KEY_I kVK_ANSI_I
#define KEY_J kVK_ANSI_J
#define KEY_K kVK_ANSI_K
#define KEY_L kVK_ANSI_L
#define KEY_M kVK_ANSI_M
#define KEY_N kVK_ANSI_N
#define KEY_O kVK_ANSI_O
#define KEY_P kVK_ANSI_P
#define KEY_Q kVK_ANSI_Q
#define KEY_R kVK_ANSI_R
#define KEY_S kVK_ANSI_S
#define KEY_T kVK_ANSI_T
#define KEY_U kVK_ANSI_U
#define KEY_V kVK_ANSI_V
#define KEY_W kVK_ANSI_W
#define KEY_X kVK_ANSI_X
#define KEY_Y kVK_ANSI_Y
#define KEY_Z kVK_ANSI_Z
#define KEY_GRAVE kVK_ANSI_Grave
#define KEY_102ND kVK_ISO_Section
#define KEY_MINUS kVK_ANSI_Minus
#define KEY_EQUAL kVK_ANSI_Equal
#define KEY_BACKSPACE kVK_Delete
#define KEY_LEFTBRACE kVK_ANSI_LeftBracket
#define KEY_RIGHTBRACE kVK_ANSI_RightBracket
#define KEY_BACKSLASH kVK_ANSI_Backslash
#define KEY_SEMICOLON kVK_ANSI_Semicolon
#define KEY_APOSTROPHE kVK_ANSI_Quote
#define KEY_ENTER kVK_Return
#define KEY_COMMA kVK_ANSI_Comma
#define KEY_DOT kVK_ANSI_Period
#define KEY_SLASH kVK_ANSI_Slash
#define KEY_SPACE kVK_Space
#define KEY_TAB kVK_Tab
#define KEY_CAPSLOCK kVK_CapsLock
#define KEY_LEFTSHIFT kVK_Shift
#define KEY_RIGHTSHIFT kVK_RightShift
#define KEY_LEFTCTRL kVK_Control
#define KEY_RIGHTCTRL kVK_RightControl
#define KEY_LEFTMETA kVK_Command
#define KEY_RIGHTMETA (kVK_Command - 1) // This isn't listed as kVK_RightCommand for some reason?
#define KEY_LEFTALT kVK_Option
#define KEY_RIGHTALT kVK_RightOption
#define KEY_COMPOSE -1 // OSX has no context menu key
#define KEY_FN kVK_Function
#define KEY_SYSRQ kVK_F13
#define KEY_SCROLLLOCK kVK_F14
#define KEY_PAUSE kVK_F15
#define KEY_INSERT kVK_Help
#define KEY_HOME kVK_Home
#define KEY_PAGEUP kVK_PageUp
#define KEY_DELETE kVK_ForwardDelete
#define KEY_END kVK_End
#define KEY_PAGEDOWN kVK_PageDown
#define KEY_UP kVK_UpArrow
#define KEY_LEFT kVK_LeftArrow
#define KEY_DOWN kVK_DownArrow
#define KEY_RIGHT kVK_RightArrow
#define KEY_NUMLOCK kVK_ANSI_KeypadClear
#define KEY_KPSLASH kVK_ANSI_KeypadDivide
#define KEY_KPASTERISK kVK_ANSI_KeypadMultiply
#define KEY_KPMINUS kVK_ANSI_KeypadMinus
#define KEY_KPPLUS kVK_ANSI_KeypadPlus
#define KEY_KPENTER kVK_ANSI_KeypadEnter
#define KEY_KPDOT kVK_ANSI_KeypadDecimal
#define KEY_KP1 kVK_ANSI_Keypad1
#define KEY_KP2 kVK_ANSI_Keypad2
#define KEY_KP3 kVK_ANSI_Keypad3
#define KEY_KP4 kVK_ANSI_Keypad4
#define KEY_KP5 kVK_ANSI_Keypad5
#define KEY_KP6 kVK_ANSI_Keypad6
#define KEY_KP7 kVK_ANSI_Keypad7
#define KEY_KP8 kVK_ANSI_Keypad8
#define KEY_KP9 kVK_ANSI_Keypad9
#define KEY_KP0 kVK_ANSI_Keypad0
#define KEY_YEN kVK_JIS_Yen
#define KEY_RO kVK_JIS_Underscore
#define KEY_KATAKANAHIRAGANA kVK_JIS_Kana
#define KEY_HENKAN -1
#define KEY_MUHENKAN -1
#define KEY_MEDIA 0x800
#define IS_MEDIA(scancode) ((scancode) >= KEY_MEDIA)
#define KEY_MUTE (KEY_MEDIA + NX_KEYTYPE_MUTE)
#define KEY_VOLUMEUP (KEY_MEDIA + NX_KEYTYPE_SOUND_UP)
#define KEY_VOLUMEDOWN (KEY_MEDIA + NX_KEYTYPE_SOUND_DOWN)
#define KEY_STOPCD -1 // OSX has no stop key
#define KEY_PREVIOUSSONG (KEY_MEDIA + NX_KEYTYPE_PREVIOUS)
#define KEY_PLAYPAUSE (KEY_MEDIA + NX_KEYTYPE_PLAY)
#define KEY_NEXTSONG (KEY_MEDIA + NX_KEYTYPE_NEXT)
#define KEY_BRIGHTNESSUP (KEY_MEDIA + NX_KEYTYPE_BRIGHTNESS_UP)
#define KEY_BRIGHTNESSDOWN (KEY_MEDIA + NX_KEYTYPE_BRIGHTNESS_DOWN)
#define KEY_EJECTCD (KEY_MEDIA + NX_KEYTYPE_EJECT)
#define KEY_POWER (KEY_MEDIA + NX_POWER_KEY)
#define BTN_LEFT 0
#define BTN_RIGHT 1
#define BTN_MIDDLE 2
#define BTN_SIDE 4
#define BTN_EXTRA 5
#define BTN_FORWARD 6
#define BTN_BACK 7
#define BTN_TASK 8
+15 -11
View File
@@ -35,11 +35,6 @@
#define UINPUT_VERSION 2
#endif
// The OSX process needs to change its EUID to post events, so thread safety must be ensured
// On Linux the EUID is always root
#define euid_guard_start
#define euid_guard_stop
#endif // OS_LINUX
#ifdef OS_MAC
@@ -61,12 +56,6 @@ typedef IOHIDDeviceDeviceInterface** hid_dev_t;
typedef IOUSBDeviceInterface182** usb_dev_t;
typedef IOUSBInterfaceInterface183** usb_iface_t;
// The OSX process needs to change its EUID to post events, so thread safety must be ensured
// On Linux the EUID is always root
extern pthread_mutex_t _euid_guard;
#define euid_guard_start pthread_mutex_lock(&_euid_guard)
#define euid_guard_stop pthread_mutex_unlock(&_euid_guard)
// Various POSIX functions that aren't present on OSX
void *memrchr(const void *s, int c, size_t n);
@@ -83,4 +72,19 @@ int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp,
#endif // OS_MAC
// The OSX process on legacy builds needs to change its EUID to post events, so thread safety must be ensured
// Otherwise the EUID is always root
#ifdef OS_MAC_LEGACY
extern pthread_mutex_t _euid_guard;
#define euid_guard_start pthread_mutex_lock(&_euid_guard)
#define euid_guard_stop pthread_mutex_unlock(&_euid_guard)
#else
#define euid_guard_start
#define euid_guard_stop
#endif // OS_MAC_LEGACY
#endif // OS_H
+5
View File
@@ -211,6 +211,10 @@ typedef struct {
kern_return_t lastresult;
// Input handle
io_connect_t event;
#ifndef OS_MAC_LEGACY
io_connect_t event_mouse;
#endif
//#ifdef OS_MAC_LEGACY //FIXME
// Key-repeat info
CFRunLoopRef input_loop;
CFRunLoopTimerRef krtimer;
@@ -220,6 +224,7 @@ typedef struct {
pthread_t indicthread;
IOOptionBits modifiers;
uchar mousestate;
//#endif
char scroll_rate;
#endif
// Number of endpoints on the USB device
+13 -4
View File
@@ -11,6 +11,8 @@
static CFRunLoopRef mainloop = 0;
static IONotificationPortRef notify = 0;
#ifdef OS_MAC_LEGACY
// Pointer to the mouse event tap. This tap lets the daemon re-insert modifier keys into
// the event stream using CoreGraphics. This is necessary because mouse events are processed
// before IOHID events according to this document: https://github.com/tekezo/Karabiner-Elements/blob/master/DEVELOPMENT.md
@@ -32,6 +34,8 @@ static CFMachPortRef mouse_event_tap;
static char current_ckb_pid;
static char mouse_event_tap_pid;
#endif
static long hidgetlong(hid_dev_t handle, CFStringRef key){
long raw = 0;
CFTypeRef cf;
@@ -269,6 +273,7 @@ static void pipecomplete(void* refcon, IOReturn result, void* arg0){
(*handle)->ReadPipeAsync(handle, ctx->pipe, buffer, ctx->maxsize, pipecomplete, ctx);
}
#ifdef OS_MAC_LEGACY
// Callback for adding modifier keys to mouse events. Every time a mouse event happens on the system
// this callback will be called and the modifier keys from the keyboard will be added to the mouse event.
CGEventRef mouse_event_modifier_callback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) {
@@ -298,7 +303,6 @@ CGEventRef mouse_event_modifier_callback(CGEventTapProxy proxy, CGEventType type
}
return event;
}
// Get the current ckb.app instance pid if it's open.
void update_ckb_pid() {
char str[10] = {0};
@@ -366,9 +370,9 @@ void register_mouse_event_tap(CFRunLoopTimerRef timer, void* info) {
}
}
// input_mac.c
// input_mac_legacy.c
extern void keyretrigger(CFRunLoopTimerRef timer, void* info);
#endif
void* os_inputmain(void* context){
usbdevice* kb = context;
@@ -426,6 +430,7 @@ void* os_inputmain(void* context){
}
}
#ifdef OS_MAC_LEGACY
// Start a timer for key repeat broadcasts
CFRunLoopTimerContext krctx = { 0, kb, NULL, NULL, NULL };
CFRunLoopTimerRef krtimer = kb->krtimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
@@ -435,7 +440,7 @@ void* os_inputmain(void* context){
CFRunLoopTimerSetTolerance(krtimer, 0.015); // Set a maximum tolerance of 15ms
// We don't actually add the timer to the run loop yet. There's no need to run the function until a key is actually pressed,
// so the timer is added and removed dynamically.
#endif
// Start the run loop
while(1){
CFRunLoopRun();
@@ -987,6 +992,8 @@ int usbmain(){
if(iterator_hid)
iterate_devices_hid(0, iterator_hid);
#ifdef OS_MAC_LEGACY
// Create a timer for register mouse event tap
CFRunLoopTimerContext rmectx = { 0, mainloop, NULL, NULL, NULL };
CFRunLoopTimerRef rmetimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
@@ -995,6 +1002,8 @@ int usbmain(){
register_mouse_event_tap, &rmectx);
CFRunLoopAddTimer(mainloop, (CFRunLoopTimerRef)rmetimer, kCFRunLoopCommonModes);
#endif
io_iterator_t iterator_syspower = 0;
IORegisterForSystemPower(NULL, &notify, powerEventCallback, &iterator_syspower);
CFRunLoopAddSource(mainloop, IONotificationPortGetRunLoopSource(notify), kCFRunLoopDefaultMode);
+8
View File
@@ -79,6 +79,14 @@ SettingsWidget::SettingsWidget(QWidget *parent) :
// Prepare extra settings
extra = new ExtraSettingsWidget(this);
#ifndef OS_MAC_LEGACY
#ifdef Q_OS_MACOS
QString labelText = ui->label_2->text();
labelText.append("<br/>Special thanks to <a href=\"https://github.com/tekezo\">tekezo</a> for <a href=\"https://github.com/tekezo/Karabiner-VirtualHIDDevice\">VirtualHIDDevice</a>.");
ui->label_2->setText(labelText);
#endif
#endif
}
SettingsWidget::~SettingsWidget(){