bool ListHookedPointing::Item::restoreEventAction(void) { if (!device_) return false; IOHIPointing* pointing = OSDynamicCast(IOHIPointing, device_); if (!pointing) return false; bool result = false; // ---------------------------------------- { RelativePointerEventCallback callback = reinterpret_cast<RelativePointerEventCallback>(pointing->_relativePointerEventAction); if (callback == EventInputQueue::push_RelativePointerEventCallback) { IOLOG_DEBUG("HookedPointing::restoreEventAction (RelativePointerEventCallback) device_:%p (%p -> %p)\n", device_, callback, orig_relativePointerEventAction_); pointing->_relativePointerEventAction = reinterpret_cast<RelativePointerEventAction>(orig_relativePointerEventAction_); result = true; } } { ScrollWheelEventCallback callback = reinterpret_cast<ScrollWheelEventCallback>(pointing->_scrollWheelEventAction); if (callback == EventInputQueue::push_ScrollWheelEventCallback) { IOLOG_DEBUG("HookedPointing::restoreEventAction (ScrollWheelEventCallback) device_:%p (%p -> %p)\n", device_, callback, orig_scrollWheelEventTarget_); pointing->_scrollWheelEventAction = reinterpret_cast<ScrollWheelEventAction>(orig_scrollWheelEventAction_); result = true; } } orig_relativePointerEventAction_ = nullptr; orig_scrollWheelEventAction_ = nullptr; orig_relativePointerEventTarget_ = nullptr; orig_scrollWheelEventTarget_ = nullptr; return result; }
bool IOHIKeyboard_gIOTerminatedNotification_callback(void* target, void* refCon, IOService* newService, IONotifier* notifier) { GlobalLock::ScopedLock lk; if (!lk) return false; IOLOG_DEBUG("%s newService:%p\n", __FUNCTION__, newService); IOHIDevice* device = OSDynamicCast(IOHIKeyboard, newService); if (!device) return false; ListHookedKeyboard::instance().erase(device); ListHookedConsumer::instance().erase(device); return true; }
bool IOHIPointing_gIOMatchedNotification_callback(void* target, void* refCon, IOService* newService, IONotifier* notifier) { GlobalLock::ScopedLock lk; if (! lk) return false; IOLOG_DEBUG("%s newService:%p\n", __FUNCTION__, newService); IOHIDevice* device = OSDynamicCast(IOHIPointing, newService); if (! device) return false; ListHookedPointing::instance().push_back(new ListHookedPointing::Item(device)); return true; }
bool notifierfunc_unhookKeyboard(void* target, void* refCon, IOService* newService, IONotifier* notifier) { IOLockWrapper::ScopedLock lk_eventlock(CommonData::getEventLock()); IOLOG_DEBUG("notifierfunc_unhookKeyboard newService:%p\n", newService); IOHIDevice* device = OSDynamicCast(IOHIKeyboard, newService); if (! device) return false; ListHookedKeyboard::instance().erase(device); ListHookedConsumer::instance().erase(device); return true; }
void ListHookedDevice::Item::setVendorProduct(void) { if (! device_) return; IORegistryEntry* dev = device_; while (dev) { const OSNumber* vid = NULL; vid = OSDynamicCast(OSNumber, dev->getProperty(kIOHIDVendorIDKey)); const OSNumber* pid = NULL; pid = OSDynamicCast(OSNumber, dev->getProperty(kIOHIDProductIDKey)); if (vid && pid) { vendor_ = vid->unsigned32BitValue(); product_ = pid->unsigned32BitValue(); goto finish; } else { // ApplePS2Keyboard does not have ProductID, // so we check for Manufacturer and Product strings const char* name = dev->getName(); if (name && strcmp(name, "ApplePS2Keyboard") == 0) { // kIOHIDManufacturerKey == "Manufacturer" // kIOHIDProductKey == "Product" const OSString* manufacturer = OSDynamicCast(OSString, dev->getProperty(kIOHIDManufacturerKey)); const OSString* product = OSDynamicCast(OSString, dev->getProperty(kIOHIDProductKey)); if (manufacturer && product) { if (manufacturer->isEqualTo("Apple") && product->isEqualTo("Keyboard")) { vendor_ = DeviceVendor::APPLE_COMPUTER; product_ = DeviceProduct::APPLE_INTERNAL_KEYBOARD_TRACKPAD_0x0218; goto finish; } } } } // check parent property. dev = dev->getParentEntry(IORegistryEntry::getPlane(kIOServicePlane)); } finish: IOLOG_DEBUG("HookedDevice::setVendorProduct device_:%p, vendor_:0x%04x, product_:0x%04x\n", device_, vendor_.get(), product_.get()); }
bool ListHookedConsumer::Item::replaceEventAction(void) { if (! device_) return false; IOHIKeyboard* kbd = OSDynamicCast(IOHIKeyboard, device_); if (! kbd) return false; KeyboardSpecialEventCallback callback = reinterpret_cast<KeyboardSpecialEventCallback>(kbd->_keyboardSpecialEventAction); if (callback == EventInputQueue::push_KeyboardSpecialEventCallback) return false; // ------------------------------------------------------------ IOLOG_DEBUG("HookedConsumer::replaceEventAction device_:%p\n", device_); orig_keyboardSpecialEventAction_ = callback; orig_keyboardSpecialEventTarget_ = kbd->_keyboardSpecialEventTarget; kbd->_keyboardSpecialEventAction = reinterpret_cast<KeyboardSpecialEventAction>(EventInputQueue::push_KeyboardSpecialEventCallback); return true; }
bool ListHookedConsumer::Item::restoreEventAction(void) { IOLockWrapper::ScopedLock lk(replacerestore_lock_); if (! lk) return false; if (! device_) return false; IOHIKeyboard* kbd = OSDynamicCast(IOHIKeyboard, device_); if (! kbd) return false; KeyboardSpecialEventCallback callback = reinterpret_cast<KeyboardSpecialEventCallback>(kbd->_keyboardSpecialEventAction); if (callback != EventInputQueue::push_KeyboardSpecialEventCallback) return false; // ---------------------------------------- IOLOG_DEBUG("HookedConsumer::restoreEventAction device_:%p\n", device_); kbd->_keyboardSpecialEventAction = reinterpret_cast<KeyboardSpecialEventAction>(orig_keyboardSpecialEventAction_); orig_keyboardSpecialEventAction_ = NULL; orig_keyboardSpecialEventTarget_ = NULL; return true; }
// ====================================================================== void EventInputQueue::push_KeyboardEventCallback(OSObject* target, unsigned int eventType, unsigned int flags, unsigned int key, unsigned int charCode, unsigned int charSet, unsigned int origCharCode, unsigned int origCharSet, unsigned int keyboardType, bool repeat, AbsoluteTime ts, OSObject* sender, void* refcon) { GlobalLock::ScopedLock lk; if (!lk) return; Params_KeyboardEventCallBack::log(true, EventType(eventType), Flags(flags), KeyCode(key), KeyboardType(keyboardType), repeat); // ------------------------------------------------------------ // Ignore unknown modifiers // // You can confirm an unknown modifier by setting key code to 255 on Seil. // This event also will be sent by Fn key on Leopold FC660M. // // KeyboardEventCallback [ caught]: eventType 12, flags 0x80000000, key 0x00ff, kbdType 43, repeat = 0 // // This key sends the same event at key pressing and key releasing. // Therefore, we cannot recognize whether key is pressed or key is released. // So, we have to ignore this key for PressingPhysicalKeys. // if (EventType::MODIFY == EventType(eventType)) { if (KeyCode(key).getModifierFlag() == ModifierFlag::ZERO) { IOLOG_DEBUG("An unknown modifier is pressed (KeyCode:0x%x, Flags:0x%x). Ignore it.\n", key, flags); return; } } // ------------------------------------------------------------ KeyboardType newkeyboardtype(keyboardType); RemapClassManager::remap_setkeyboardtype(newkeyboardtype); KeyCode newkey(key); Flags newflags(flags); KeyCode::normalizeKey(newkey, newflags, EventType(eventType), newkeyboardtype); // ------------------------------------------------------------ Params_KeyboardEventCallBack params(EventType(eventType), newflags, newkey, CharCode(charCode), CharSet(charSet), OrigCharCode(origCharCode), OrigCharSet(origCharSet), newkeyboardtype, repeat); // ------------------------------------------------------------ IOHIKeyboard* device = OSDynamicCast(IOHIKeyboard, sender); if (!device) return; ListHookedKeyboard::Item* item = static_cast<ListHookedKeyboard::Item*>(ListHookedKeyboard::instance().get(device)); if (!item) return; // ------------------------------------------------------------ // Device Hacks // Drop events if "Disable an internal keyboard while external keyboards are connected" is enabled. if (Config::get_essential_config(BRIDGE_ESSENTIAL_CONFIG_INDEX_general_disable_internal_keyboard_if_external_keyboard_exsits)) { if (item->isInternalDevice() && ListHookedKeyboard::instance().isExternalDevicesConnected()) { return; } } // Logitech Cordless Presenter (LCP) Hack // // When an LCP is first plugged in, it will send a CONTROL_L down event // when the first pageup/pagedown key is pressed without sending a corresponding // up event -- effectively rendering the device (and the Mac) useless until it is // unplugged from the system. // // Similarly, when the volume keys are first pressed, a SHIFT_L down event // is generated, with now up event. // // This code effectively throws these events away if they are received from an LCP. // // *** LCP has 6 keys (Page Up, Page Down, a 'B' key, an 'Esc' key, and volume up / down keys). *** // *** So, we can drop CONTROL_L and SHIFT_L without a problem. *** if ((item->getDeviceIdentifier()).isEqualVendorProduct(DeviceVendor::LOGITECH, DeviceProduct::LOGITECH_CORDLESS_PRESENTER)) { if (params.key == KeyCode::CONTROL_L) return; if (params.key == KeyCode::SHIFT_L) return; } // ------------------------------------------------------------ // NumLock Hacks // // As for some keypads, NumLock is off when it was connected. // We need to call setAlphaLock(true) to activate a device. RemapClassManager::remap_forcenumlockon(item); // ------------------------------------------------------------ CommonData::setcurrent_ts(ts); // ------------------------------------------------------------ // Because we handle the key repeat ourself, drop the key repeat by hardware. if (repeat) return; // ------------------------------------------------------------ bool retainFlagStatusTemporaryCount = false; bool push_back = true; bool isSimultaneousKeyPressesTarget = true; enqueue_(params, retainFlagStatusTemporaryCount, item->getDeviceIdentifier(), push_back, isSimultaneousKeyPressesTarget); setTimer(); }
void ListHookedDevice::Item::setDeviceType(void) { if (!device_) return; const char* name = nullptr; name = device_->getName(); if (!name) goto finish; // Apple device if (strcmp(name, "IOHIDKeyboard") == 0 || strcmp(name, "AppleADBKeyboard") == 0 || strcmp(name, "IOHIDConsumer") == 0 || strcmp(name, "IOHIDPointing") == 0 || strcmp(name, "ApplePS2Mouse") == 0 || strcmp(name, "ApplePS2Trackpad") == 0 || strcmp(name, "AppleUSBGrIIITrackpad") == 0 || strcmp(name, "AppleADBMouseType4") == 0) { deviceType_ = DeviceType::APPLE_EXTERNAL; // ------------------------------------------------------------ // Judge internal device or external device. // // We judge it from a product name whether it is internal device. // At keyboard, we cannot use the KeyboardType, // because some external keyboard has the same KeyboardType as Apple internal keyboard. const OSString* productname = nullptr; productname = OSDynamicCast(OSString, device_->getProperty(kIOHIDProductKey)); if (productname) { const char* pname = productname->getCStringNoCopy(); if (pname) { const char* internalname = "Apple Internal "; if (strncmp(internalname, pname, strlen(internalname)) == 0) { deviceType_ = DeviceType::APPLE_INTERNAL; } const char* mikeyname = "Apple Mikey HID Driver"; if (strcmp(mikeyname, pname) == 0) { deviceType_ = DeviceType::APPLE_MIKEY_HID_DRIVER; } } } goto finish; } if (strcmp(name, "ApplePS2Keyboard") == 0) { deviceType_ = DeviceType::APPLE_INTERNAL; goto finish; } // USB Overdrive if (strcmp(name, "OverdriveHIDKeyboard") == 0 || strcmp(name, "OverdriveHIDPointer") == 0) { deviceType_ = DeviceType::USB_OVERDRIVE; goto finish; } finish: IOLOG_DEBUG("HookedDevice::setDeviceType device_:%p, name:%s, deviceType_:%d\n", device_, name ? name : "null", deviceType_); }
ListHookedConsumer::Item::~Item(void) { IOLOG_DEBUG("ListHookedConsumer::Item::~Item()\n"); restoreEventAction(); }
// ---------------------------------------- static void log(bool isCaught, Flags flags) { IOLOG_DEBUG("UpdateEventFlagsCallback [%7s]: flags 0x%08x\n", isCaught ? "caught" : "sending", flags.get()); }
// ---------------------------------------- static void log(bool isCaught, EventType eventType, Flags flags, KeyCode key, KeyboardType keyboardType, bool repeat) { IOLOG_DEBUG("KeyboardEventCallback [%7s]: eventType %2d, flags 0x%08x, key 0x%04x, kbdType %3d, repeat = %d\n", isCaught ? "caught" : "sending", eventType.get(), flags.get(), key.get(), keyboardType.get(), repeat); }
// ---------------------------------------- static void log(bool isCaught, EventType eventType, Flags flags, ConsumerKeyCode key, unsigned int flavor, UInt64 guid, bool repeat) { IOLOG_DEBUG("KeyboardSpecialEventCallBack [%7s]: eventType %2d, flags 0x%08x, key 0x%04x, flavor %4d, guid %lld, repeat = %d\n", isCaught ? "caught" : "sending", eventType.get(), flags.get(), key.get(), flavor, guid, repeat); }
ListHookedKeyboard::Item::~Item(void) { IOLOG_DEBUG("ListHookedKeyboard::Item::~Item()\n"); restoreEventAction(); }
ListHookedConsumer::Item::~Item(void) { IOLOG_DEBUG("ListHookedConsumer::Item::~Item()\n"); restoreEventAction(); IOLockWrapper::free(replacerestore_lock_); }
ListHookedPointing::Item::~Item(void) { IOLOG_DEBUG("ListHookedPointing::Item::~Item()\n"); restoreEventAction(); }