mirror of
https://github.com/ckb-next/ckb-next.git
synced 2026-10-10 12:27:21 -04:00
Use VirtualHIDDevice for keyboards and mice
This commit is contained in:
+77
@@ -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>
|
||||||
Executable
BIN
Binary file not shown.
Executable
+115
@@ -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>
|
||||||
@@ -89,6 +89,7 @@ if (MACOS OR LINUX)
|
|||||||
firmware.h
|
firmware.h
|
||||||
includes.h
|
includes.h
|
||||||
input.h
|
input.h
|
||||||
|
input_mac_vhid.h
|
||||||
keymap.h
|
keymap.h
|
||||||
keymap_patch.h
|
keymap_patch.h
|
||||||
led.h
|
led.h
|
||||||
@@ -105,7 +106,7 @@ if (MACOS)
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
usb_mac.c
|
usb_mac.c
|
||||||
input_mac.c
|
input_mac.c
|
||||||
input_mac_mouse.c
|
input_mac_mouse_legacy.c
|
||||||
extra_mac.c
|
extra_mac.c
|
||||||
keymap_mac.h)
|
keymap_mac.h)
|
||||||
elseif (LINUX)
|
elseif (LINUX)
|
||||||
|
|||||||
+89
-367
@@ -3,299 +3,88 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
|
||||||
#ifdef OS_MAC
|
#ifdef OS_MAC
|
||||||
|
#ifndef OS_MAC_LEGACY
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
|
#include "input_mac_vhid.h"
|
||||||
|
|
||||||
int osx_ver = -1;
|
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
|
// VirtualHIDPointing
|
||||||
#define IS_NUMPAD(scancode) ((scancode) >= kVK_ANSI_KeypadDecimal && (scancode) <= kVK_ANSI_Keypad9 && (scancode) != kVK_ANSI_KeypadClear && (scancode) != kVK_ANSI_KeypadEnter)
|
vhid_mouseinput mouseinput = {{0}, 0, 0, 0, 0};
|
||||||
|
|
||||||
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){
|
int os_inputopen(usbdevice* kb){
|
||||||
// The IO service isn't always ready at startup, so if it's not, wait until it is
|
// Check if Karabiner VirtualHIDDevice is loaded
|
||||||
IOReturn res;
|
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceNameMatching(VIRTUAL_HID_ROOT_NAME));
|
||||||
while((res = open_iohid(&kb->event)) != kIOReturnSuccess){
|
if(!service)
|
||||||
if(res != kIOReturnNotOpen){
|
ckb_fatal("Unable to open VirtualHIDDevice\n");
|
||||||
// If this is a more serious error, at least print a warning
|
|
||||||
ckb_err("Unable to open HID system: 0x%08x\n", res);
|
kern_return_t kr;
|
||||||
sleep(1);
|
kr = IOServiceOpen(service, mach_task_self(), kIOHIDServerConnectType, &(kb->event));
|
||||||
continue;
|
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);
|
clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec) {.tv_nsec = 10000000}, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
clearkeys(kb);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void os_inputclose(usbdevice* kb){
|
void os_inputclose(usbdevice* kb){
|
||||||
if(kb->event){
|
if(kb->event){
|
||||||
clearkeys(kb);
|
|
||||||
IOServiceClose(kb->event);
|
IOServiceClose(kb->event);
|
||||||
kb->event = 0;
|
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.
|
// 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.
|
// 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.
|
// 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){
|
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 & 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)
|
if(down)
|
||||||
postevent_wheel(kb->event, kb->scroll_rate, 1);
|
add_to_buttons(scan, &mouseinput);
|
||||||
return;
|
else
|
||||||
} else if(scancode == BTN_WHEELDOWN){
|
remove_from_buttons(scan, &mouseinput);
|
||||||
if(down)
|
|
||||||
postevent_wheel(kb->event, kb->scroll_rate, -1);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
int button = scancode & ~SCAN_MOUSE;
|
IOConnectCallStructMethod(kb->event_mouse, post_pointing_input_report, &mouseinput, sizeof(mouseinput), NULL, 0);
|
||||||
// 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;
|
return;
|
||||||
}
|
}
|
||||||
// Some boneheaded Apple engineers decided to reverse kVK_ANSI_Grave and kVK_ISO_Section on the 105-key layouts...
|
ckb_info("scancode %x\n", scancode);
|
||||||
if(!HAS_ANY_FEATURE(kb, FEAT_LMASK)){
|
// Pick the appropriate add or remove function
|
||||||
// If the layout hasn't been set yet, it can be auto-detected from certain keys
|
add_remove_keys = down ? &add_to_keys : &remove_from_keys;
|
||||||
if(scancode == KEY_BACKSLASH_ISO || scancode == KEY_102ND)
|
|
||||||
kb->features |= FEAT_ISO;
|
if(IS_VENDOR(scancode)) { // Fn
|
||||||
else if(scancode == KEY_BACKSLASH)
|
scancode = scancode - KEY_CONSUMER;
|
||||||
kb->features |= FEAT_ANSI;
|
(*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);
|
||||||
}
|
}
|
||||||
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){
|
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){
|
int os_setupindicators(usbdevice* kb){
|
||||||
@@ -431,3 +152,4 @@ int os_setupindicators(usbdevice* kb){
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -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"
|
#include "includes.h"
|
||||||
|
|
||||||
#ifdef OS_MAC
|
#ifdef OS_MAC_LEGACY
|
||||||
|
|
||||||
// Most of this code shamelessly stolen from:
|
// Most of this code shamelessly stolen from:
|
||||||
// http://www.opensource.apple.com/source/IOHIDFamily/IOHIDFamily-606.1.7/IOHIDSystem/IOHIPointing.cpp
|
// 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);
|
pthread_mutex_unlock(&mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // OS_MAC
|
#endif // OS_MAC_LEGACY
|
||||||
@@ -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
@@ -4,163 +4,173 @@
|
|||||||
#include "os.h"
|
#include "os.h"
|
||||||
#ifdef OS_MAC
|
#ifdef OS_MAC
|
||||||
|
|
||||||
// Emulate Linux key constants for OSX
|
#ifdef OS_MAC_LEGACY
|
||||||
|
|
||||||
#define KEY_ESC kVK_Escape
|
#include "keymap_mac_legacy.h"
|
||||||
#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
|
#else
|
||||||
#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
|
// Replace Linux key constants with HID scancodes for macOS w/VirtualHIDDevice
|
||||||
#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_ESC kHIDUsage_KeyboardEscape
|
||||||
#define KEY_102ND kVK_ISO_Section
|
#define KEY_F1 kHIDUsage_KeyboardF1
|
||||||
#define KEY_MINUS kVK_ANSI_Minus
|
#define KEY_F2 kHIDUsage_KeyboardF2
|
||||||
#define KEY_EQUAL kVK_ANSI_Equal
|
#define KEY_F3 kHIDUsage_KeyboardF3
|
||||||
#define KEY_BACKSPACE kVK_Delete
|
#define KEY_F4 kHIDUsage_KeyboardF4
|
||||||
#define KEY_LEFTBRACE kVK_ANSI_LeftBracket
|
#define KEY_F5 kHIDUsage_KeyboardF5
|
||||||
#define KEY_RIGHTBRACE kVK_ANSI_RightBracket
|
#define KEY_F6 kHIDUsage_KeyboardF6
|
||||||
#define KEY_BACKSLASH kVK_ANSI_Backslash
|
#define KEY_F7 kHIDUsage_KeyboardF7
|
||||||
#define KEY_SEMICOLON kVK_ANSI_Semicolon
|
#define KEY_F8 kHIDUsage_KeyboardF8
|
||||||
#define KEY_APOSTROPHE kVK_ANSI_Quote
|
#define KEY_F9 kHIDUsage_KeyboardF9
|
||||||
#define KEY_ENTER kVK_Return
|
#define KEY_F10 kHIDUsage_KeyboardF10
|
||||||
#define KEY_COMMA kVK_ANSI_Comma
|
#define KEY_F11 kHIDUsage_KeyboardF11
|
||||||
#define KEY_DOT kVK_ANSI_Period
|
#define KEY_F12 kHIDUsage_KeyboardF12
|
||||||
#define KEY_SLASH kVK_ANSI_Slash
|
#define KEY_F13 kHIDUsage_KeyboardF13
|
||||||
#define KEY_SPACE kVK_Space
|
#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_1 kHIDUsage_Keyboard1
|
||||||
#define KEY_CAPSLOCK kVK_CapsLock
|
#define KEY_2 kHIDUsage_Keyboard2
|
||||||
#define KEY_LEFTSHIFT kVK_Shift
|
#define KEY_3 kHIDUsage_Keyboard3
|
||||||
#define KEY_RIGHTSHIFT kVK_RightShift
|
#define KEY_4 kHIDUsage_Keyboard4
|
||||||
#define KEY_LEFTCTRL kVK_Control
|
#define KEY_5 kHIDUsage_Keyboard5
|
||||||
#define KEY_RIGHTCTRL kVK_RightControl
|
#define KEY_6 kHIDUsage_Keyboard6
|
||||||
#define KEY_LEFTMETA kVK_Command
|
#define KEY_7 kHIDUsage_Keyboard7
|
||||||
#define KEY_RIGHTMETA (kVK_Command - 1) // This isn't listed as kVK_RightCommand for some reason?
|
#define KEY_8 kHIDUsage_Keyboard8
|
||||||
#define KEY_LEFTALT kVK_Option
|
#define KEY_9 kHIDUsage_Keyboard9
|
||||||
#define KEY_RIGHTALT kVK_RightOption
|
#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_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_SYSRQ kHIDUsage_KeyboardF13
|
||||||
#define KEY_SCROLLLOCK kVK_F14
|
#define KEY_SCROLLLOCK kHIDUsage_KeyboardF14
|
||||||
#define KEY_PAUSE kVK_F15
|
#define KEY_PAUSE kHIDUsage_KeyboardF15
|
||||||
#define KEY_INSERT kVK_Help
|
#define KEY_INSERT kHIDUsage_KeyboardInsert
|
||||||
#define KEY_HOME kVK_Home
|
#define KEY_HOME kHIDUsage_KeyboardHome
|
||||||
#define KEY_PAGEUP kVK_PageUp
|
#define KEY_PAGEUP kHIDUsage_KeyboardPageUp
|
||||||
#define KEY_DELETE kVK_ForwardDelete
|
#define KEY_DELETE kHIDUsage_KeyboardDeleteForward
|
||||||
#define KEY_END kVK_End
|
#define KEY_END kHIDUsage_KeyboardEnd
|
||||||
#define KEY_PAGEDOWN kVK_PageDown
|
#define KEY_PAGEDOWN kHIDUsage_KeyboardPageDown
|
||||||
|
|
||||||
#define KEY_UP kVK_UpArrow
|
#define KEY_UP kHIDUsage_KeyboardUpArrow
|
||||||
#define KEY_LEFT kVK_LeftArrow
|
#define KEY_LEFT kHIDUsage_KeyboardLeftArrow
|
||||||
#define KEY_DOWN kVK_DownArrow
|
#define KEY_DOWN kHIDUsage_KeyboardDownArrow
|
||||||
#define KEY_RIGHT kVK_RightArrow
|
#define KEY_RIGHT kHIDUsage_KeyboardRightArrow
|
||||||
|
|
||||||
#define KEY_NUMLOCK kVK_ANSI_KeypadClear
|
#define KEY_NUMLOCK kHIDUsage_KeypadNumLock
|
||||||
#define KEY_KPSLASH kVK_ANSI_KeypadDivide
|
#define KEY_KPSLASH kHIDUsage_KeypadSlash
|
||||||
#define KEY_KPASTERISK kVK_ANSI_KeypadMultiply
|
#define KEY_KPASTERISK kHIDUsage_KeypadAsterisk
|
||||||
#define KEY_KPMINUS kVK_ANSI_KeypadMinus
|
#define KEY_KPMINUS kHIDUsage_KeypadHyphen
|
||||||
#define KEY_KPPLUS kVK_ANSI_KeypadPlus
|
#define KEY_KPPLUS kHIDUsage_KeypadPlus
|
||||||
#define KEY_KPENTER kVK_ANSI_KeypadEnter
|
#define KEY_KPENTER kHIDUsage_KeypadEnter
|
||||||
#define KEY_KPDOT kVK_ANSI_KeypadDecimal
|
#define KEY_KPDOT kHIDUsage_KeypadPeriod
|
||||||
#define KEY_KP1 kVK_ANSI_Keypad1
|
#define KEY_KP1 kHIDUsage_Keypad1
|
||||||
#define KEY_KP2 kVK_ANSI_Keypad2
|
#define KEY_KP2 kHIDUsage_Keypad2
|
||||||
#define KEY_KP3 kVK_ANSI_Keypad3
|
#define KEY_KP3 kHIDUsage_Keypad3
|
||||||
#define KEY_KP4 kVK_ANSI_Keypad4
|
#define KEY_KP4 kHIDUsage_Keypad4
|
||||||
#define KEY_KP5 kVK_ANSI_Keypad5
|
#define KEY_KP5 kHIDUsage_Keypad5
|
||||||
#define KEY_KP6 kVK_ANSI_Keypad6
|
#define KEY_KP6 kHIDUsage_Keypad6
|
||||||
#define KEY_KP7 kVK_ANSI_Keypad7
|
#define KEY_KP7 kHIDUsage_Keypad7
|
||||||
#define KEY_KP8 kVK_ANSI_Keypad8
|
#define KEY_KP8 kHIDUsage_Keypad8
|
||||||
#define KEY_KP9 kVK_ANSI_Keypad9
|
#define KEY_KP9 kHIDUsage_Keypad9
|
||||||
#define KEY_KP0 kVK_ANSI_Keypad0
|
#define KEY_KP0 kHIDUsage_Keypad0
|
||||||
|
|
||||||
#define KEY_YEN kVK_JIS_Yen
|
#define KEY_YEN kHIDUsage_KeyboardInternational3
|
||||||
#define KEY_RO kVK_JIS_Underscore
|
#define KEY_RO kHIDUsage_KeyboardInternational1
|
||||||
#define KEY_KATAKANAHIRAGANA kVK_JIS_Kana
|
#define KEY_KATAKANAHIRAGANA kHIDUsage_KeyboardInternational2
|
||||||
#define KEY_HENKAN -1
|
#define KEY_HENKAN kHIDUsage_KeyboardInternational4
|
||||||
#define KEY_MUHENKAN -1
|
#define KEY_MUHENKAN kHIDUsage_KeyboardInternational5
|
||||||
|
|
||||||
#define KEY_MEDIA 0x800
|
#define KEY_CONSUMER 0x800
|
||||||
#define IS_MEDIA(scancode) ((scancode) >= KEY_MEDIA)
|
#define IS_CONSUMER(scan) ((scan) >= KEY_CONSUMER)
|
||||||
#define KEY_MUTE (KEY_MEDIA + NX_KEYTYPE_MUTE)
|
#define KEY_MUTE (KEY_CONSUMER + kHIDUsage_Csmr_Mute)
|
||||||
#define KEY_VOLUMEUP (KEY_MEDIA + NX_KEYTYPE_SOUND_UP)
|
#define KEY_VOLUMEUP (KEY_CONSUMER + kHIDUsage_Csmr_VolumeIncrement)
|
||||||
#define KEY_VOLUMEDOWN (KEY_MEDIA + NX_KEYTYPE_SOUND_DOWN)
|
#define KEY_VOLUMEDOWN (KEY_CONSUMER + kHIDUsage_Csmr_VolumeDecrement)
|
||||||
#define KEY_STOPCD -1 // OSX has no stop key
|
#define KEY_STOPCD (KEY_CONSUMER + kHIDUsage_Csmr_Stop)
|
||||||
#define KEY_PREVIOUSSONG (KEY_MEDIA + NX_KEYTYPE_PREVIOUS)
|
#define KEY_PREVIOUSSONG (KEY_CONSUMER + kHIDUsage_Csmr_ScanPreviousTrack)
|
||||||
#define KEY_PLAYPAUSE (KEY_MEDIA + NX_KEYTYPE_PLAY)
|
#define KEY_PLAYPAUSE (KEY_CONSUMER + kHIDUsage_Csmr_PlayOrPause)
|
||||||
#define KEY_NEXTSONG (KEY_MEDIA + NX_KEYTYPE_NEXT)
|
#define KEY_NEXTSONG (KEY_CONSUMER + kHIDUsage_Csmr_ScanNextTrack)
|
||||||
#define KEY_BRIGHTNESSUP (KEY_MEDIA + NX_KEYTYPE_BRIGHTNESS_UP)
|
#define KEY_BRIGHTNESSUP (KEY_CONSUMER + 0x0020)
|
||||||
#define KEY_BRIGHTNESSDOWN (KEY_MEDIA + NX_KEYTYPE_BRIGHTNESS_DOWN)
|
#define KEY_BRIGHTNESSDOWN (KEY_CONSUMER + 0x0021)
|
||||||
#define KEY_EJECTCD (KEY_MEDIA + NX_KEYTYPE_EJECT)
|
#define KEY_EJECTCD (KEY_CONSUMER + kHIDUsage_Csmr_Eject)
|
||||||
#define KEY_POWER (KEY_MEDIA + NX_POWER_KEY)
|
#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_LEFT 1
|
||||||
#define BTN_MIDDLE 2
|
#define BTN_RIGHT 2
|
||||||
|
#define BTN_MIDDLE 3
|
||||||
#define BTN_SIDE 4
|
#define BTN_SIDE 4
|
||||||
#define BTN_EXTRA 5
|
#define BTN_EXTRA 5
|
||||||
#define BTN_FORWARD 6
|
#define BTN_FORWARD 6
|
||||||
#define BTN_BACK 7
|
#define BTN_BACK 7
|
||||||
#define BTN_TASK 8
|
#define BTN_TASK 8
|
||||||
|
|
||||||
|
#endif //OS_MAC_LEGACY
|
||||||
|
|
||||||
#endif // OS_MAC
|
#endif // OS_MAC
|
||||||
|
|
||||||
#endif // KEYMAP_MAC_H
|
#endif // KEYMAP_MAC_H
|
||||||
|
|||||||
@@ -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
@@ -35,11 +35,6 @@
|
|||||||
#define UINPUT_VERSION 2
|
#define UINPUT_VERSION 2
|
||||||
#endif
|
#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
|
#endif // OS_LINUX
|
||||||
|
|
||||||
#ifdef OS_MAC
|
#ifdef OS_MAC
|
||||||
@@ -61,12 +56,6 @@ typedef IOHIDDeviceDeviceInterface** hid_dev_t;
|
|||||||
typedef IOUSBDeviceInterface182** usb_dev_t;
|
typedef IOUSBDeviceInterface182** usb_dev_t;
|
||||||
typedef IOUSBInterfaceInterface183** usb_iface_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
|
// Various POSIX functions that aren't present on OSX
|
||||||
|
|
||||||
void *memrchr(const void *s, int c, size_t n);
|
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
|
#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
|
#endif // OS_H
|
||||||
|
|||||||
@@ -211,6 +211,10 @@ typedef struct {
|
|||||||
kern_return_t lastresult;
|
kern_return_t lastresult;
|
||||||
// Input handle
|
// Input handle
|
||||||
io_connect_t event;
|
io_connect_t event;
|
||||||
|
#ifndef OS_MAC_LEGACY
|
||||||
|
io_connect_t event_mouse;
|
||||||
|
#endif
|
||||||
|
//#ifdef OS_MAC_LEGACY //FIXME
|
||||||
// Key-repeat info
|
// Key-repeat info
|
||||||
CFRunLoopRef input_loop;
|
CFRunLoopRef input_loop;
|
||||||
CFRunLoopTimerRef krtimer;
|
CFRunLoopTimerRef krtimer;
|
||||||
@@ -220,6 +224,7 @@ typedef struct {
|
|||||||
pthread_t indicthread;
|
pthread_t indicthread;
|
||||||
IOOptionBits modifiers;
|
IOOptionBits modifiers;
|
||||||
uchar mousestate;
|
uchar mousestate;
|
||||||
|
//#endif
|
||||||
char scroll_rate;
|
char scroll_rate;
|
||||||
#endif
|
#endif
|
||||||
// Number of endpoints on the USB device
|
// Number of endpoints on the USB device
|
||||||
|
|||||||
+13
-4
@@ -11,6 +11,8 @@
|
|||||||
static CFRunLoopRef mainloop = 0;
|
static CFRunLoopRef mainloop = 0;
|
||||||
static IONotificationPortRef notify = 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
|
// 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
|
// 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
|
// 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 current_ckb_pid;
|
||||||
static char mouse_event_tap_pid;
|
static char mouse_event_tap_pid;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static long hidgetlong(hid_dev_t handle, CFStringRef key){
|
static long hidgetlong(hid_dev_t handle, CFStringRef key){
|
||||||
long raw = 0;
|
long raw = 0;
|
||||||
CFTypeRef cf;
|
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);
|
(*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
|
// 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.
|
// 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) {
|
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;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the current ckb.app instance pid if it's open.
|
// Get the current ckb.app instance pid if it's open.
|
||||||
void update_ckb_pid() {
|
void update_ckb_pid() {
|
||||||
char str[10] = {0};
|
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);
|
extern void keyretrigger(CFRunLoopTimerRef timer, void* info);
|
||||||
|
#endif
|
||||||
void* os_inputmain(void* context){
|
void* os_inputmain(void* context){
|
||||||
usbdevice* kb = context;
|
usbdevice* kb = context;
|
||||||
|
|
||||||
@@ -426,6 +430,7 @@ void* os_inputmain(void* context){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef OS_MAC_LEGACY
|
||||||
// Start a timer for key repeat broadcasts
|
// Start a timer for key repeat broadcasts
|
||||||
CFRunLoopTimerContext krctx = { 0, kb, NULL, NULL, NULL };
|
CFRunLoopTimerContext krctx = { 0, kb, NULL, NULL, NULL };
|
||||||
CFRunLoopTimerRef krtimer = kb->krtimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
|
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
|
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,
|
// 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.
|
// so the timer is added and removed dynamically.
|
||||||
|
#endif
|
||||||
// Start the run loop
|
// Start the run loop
|
||||||
while(1){
|
while(1){
|
||||||
CFRunLoopRun();
|
CFRunLoopRun();
|
||||||
@@ -987,6 +992,8 @@ int usbmain(){
|
|||||||
if(iterator_hid)
|
if(iterator_hid)
|
||||||
iterate_devices_hid(0, iterator_hid);
|
iterate_devices_hid(0, iterator_hid);
|
||||||
|
|
||||||
|
#ifdef OS_MAC_LEGACY
|
||||||
|
|
||||||
// Create a timer for register mouse event tap
|
// Create a timer for register mouse event tap
|
||||||
CFRunLoopTimerContext rmectx = { 0, mainloop, NULL, NULL, NULL };
|
CFRunLoopTimerContext rmectx = { 0, mainloop, NULL, NULL, NULL };
|
||||||
CFRunLoopTimerRef rmetimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
|
CFRunLoopTimerRef rmetimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
|
||||||
@@ -995,6 +1002,8 @@ int usbmain(){
|
|||||||
register_mouse_event_tap, &rmectx);
|
register_mouse_event_tap, &rmectx);
|
||||||
CFRunLoopAddTimer(mainloop, (CFRunLoopTimerRef)rmetimer, kCFRunLoopCommonModes);
|
CFRunLoopAddTimer(mainloop, (CFRunLoopTimerRef)rmetimer, kCFRunLoopCommonModes);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
io_iterator_t iterator_syspower = 0;
|
io_iterator_t iterator_syspower = 0;
|
||||||
IORegisterForSystemPower(NULL, ¬ify, powerEventCallback, &iterator_syspower);
|
IORegisterForSystemPower(NULL, ¬ify, powerEventCallback, &iterator_syspower);
|
||||||
CFRunLoopAddSource(mainloop, IONotificationPortGetRunLoopSource(notify), kCFRunLoopDefaultMode);
|
CFRunLoopAddSource(mainloop, IONotificationPortGetRunLoopSource(notify), kCFRunLoopDefaultMode);
|
||||||
|
|||||||
@@ -79,6 +79,14 @@ SettingsWidget::SettingsWidget(QWidget *parent) :
|
|||||||
|
|
||||||
// Prepare extra settings
|
// Prepare extra settings
|
||||||
extra = new ExtraSettingsWidget(this);
|
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(){
|
SettingsWidget::~SettingsWidget(){
|
||||||
|
|||||||
Reference in New Issue
Block a user