Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added message capability for sending key to primary keyboard #5

Merged
merged 5 commits into from
Oct 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions BrightnessKeys.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"MODULE_VERSION=$(MODULE_VERSION)",
"PRODUCT_NAME=$(PRODUCT_NAME)",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
Expand Down Expand Up @@ -276,6 +277,7 @@
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"MODULE_VERSION=$(MODULE_VERSION)",
"PRODUCT_NAME=$(PRODUCT_NAME)",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
Expand All @@ -295,6 +297,7 @@
3573FE3925223B8500DFC9F4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(NATIVE_ARCH_ACTUAL)";
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
Expand All @@ -318,6 +321,7 @@
3573FE3A25223B8500DFC9F4 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(NATIVE_ARCH_ACTUAL)";
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
Expand Down
186 changes: 146 additions & 40 deletions BrightnessKeys/BrightnessKeys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,29 @@
#include <Headers/kern_version.hpp>
#include "BrightnessKeys.hpp"

bool ADDPR(debugEnabled) = false;
uint32_t ADDPR(debugPrintDelay) = 0;

#define kDeliverNotifications "RM,deliverNotifications"

// Constants for keyboards
enum
{
kPS2K_notifyKeystroke = iokit_vendor_specific_msg(202), // notify of key press (data is PS2KeyInfo*)
};

typedef struct PS2KeyInfo
{
uint64_t time;
UInt16 adbKeyCode;
bool goingDown;
bool eatKey;
} PS2KeyInfo;

// Constants for brightness keys

#define kBrightnessPanel "BrightnessPanel"
#define kBrightnessKey "BrightnessKey"

#ifdef DEBUG
#define DEBUG_LOG(args...) do { IOLog(args); } while (0)
#else
#define DEBUG_LOG(args...) do { } while (0)
#endif
#define kBrightnessKey "BrightnessKeyRouted"

#define BRIGHTNESS_DOWN 0x6b
#define BRIGHTNESS_UP 0x71
Expand All @@ -26,21 +38,6 @@

OSDefineMetaClassAndStructors(BrightnessKeys, super)

bool BrightnessKeys::init() {
if (!super::init())
return false;
// initialize ACPI support for brightness key
_panel = 0;
_panelFallback = 0;
_panelDiscrete = 0;
_panelNotified = false;
_panelPrompt = false;
_panelNotifiers = 0;
_panelNotifiersFallback = 0;
_panelNotifiersDiscrete = 0;
return true;
}

IORegistryEntry* BrightnessKeys::getDeviceByAddress(IORegistryEntry *parent, UInt64 address, UInt64 mask) {
IORegistryEntry* child = NULL;
auto iter = parent->getChildIterator(gIODTPlane);
Expand Down Expand Up @@ -136,6 +133,36 @@ bool BrightnessKeys::start(IOService *provider) {

setProperty("VersionInfo", kextVersion);

ADDPR(debugEnabled) = checkKernelArgument("-brkeysdbg") || checkKernelArgument("-liludbgall");
PE_parse_boot_argn("liludelay", &ADDPR(debugPrintDelay), sizeof(ADDPR(debugPrintDelay)));

workLoop = IOWorkLoop::workLoop();
commandGate = IOCommandGate::commandGate(this);
if (!workLoop || !commandGate || (workLoop->addEventSource(commandGate) != kIOReturnSuccess)) {
SYSLOG("brkeys", "failed to add commandGate");
return false;
}

_notificationServices = OSSet::withCapacity(1);
_deliverNotification = OSSymbol::withCString(kDeliverNotifications);
if (!_notificationServices || !_deliverNotification) {
SYSLOG("brkeys", "failed to add notification service");
return false;
}

OSDictionary * propertyMatch = propertyMatching(_deliverNotification, kOSBooleanTrue);
if (propertyMatch) {
IOServiceMatchingNotificationHandler notificationHandler = OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &BrightnessKeys::notificationHandler);

//
// Register notifications for availability of any IOService objects wanting to consume our message events
//
_publishNotify = addMatchingNotification(gIOFirstPublishNotification, propertyMatch, notificationHandler, this, 0, 10000);
_terminateNotify = addMatchingNotification(gIOTerminatedNotification, propertyMatch, notificationHandler, this, 0, 10000);

propertyMatch->release();
}

// get IOACPIPlatformDevice for built-in panel
getBrightnessPanel();

Expand All @@ -149,7 +176,7 @@ bool BrightnessKeys::start(IOService *provider) {
_panelNotifiersDiscrete = _panelDiscrete->registerInterest(gIOGeneralInterest, _panelNotification, this);

if (_panelNotifiers == NULL && _panelNotifiersFallback == NULL && _panelNotifiersDiscrete == NULL) {
IOLog("ps2br: unable to register any interests for GFX notifications\n");
SYSLOG("brkeys", "unable to register any interests for GFX notifications");
return false;
}

Expand All @@ -174,65 +201,144 @@ void BrightnessKeys::stop(IOService *provider) {
OSSafeReleaseNULL(_panel);
OSSafeReleaseNULL(_panelFallback);
OSSafeReleaseNULL(_panelDiscrete);

_publishNotify->remove();
_terminateNotify->remove();
_notificationServices->flushCollection();
OSSafeReleaseNULL(_notificationServices);
OSSafeReleaseNULL(_deliverNotification);

workLoop->removeEventSource(commandGate);
OSSafeReleaseNULL(commandGate);
OSSafeReleaseNULL(workLoop);

super::stop(provider);
}

IOReturn BrightnessKeys::_panelNotification(void *target, void *refCon, UInt32 messageType, IOService *provider, void *messageArgument, vm_size_t argSize) {
if (messageType == kIOACPIMessageDeviceNotification) {
if (NULL == target) {
DEBUG_LOG("%s kIOACPIMessageDeviceNotification target is null\n", provider->getName());
DBGLOG("brkeys", "%s kIOACPIMessageDeviceNotification target is null", provider->getName());
return kIOReturnError;
}

auto self = OSDynamicCast(BrightnessKeys, reinterpret_cast<OSMetaClassBase*>(target));
if (NULL == self) {
DEBUG_LOG("%s kIOACPIMessageDeviceNotification target is not a ApplePS2Keyboard\n", provider->getName());
DBGLOG("brkeys", "%s kIOACPIMessageDeviceNotification target is not a ApplePS2Keyboard\n", provider->getName());
return kIOReturnError;
}

if (NULL != messageArgument) {
uint64_t now_abs;
PS2KeyInfo info;
UInt32 arg = *static_cast<UInt32*>(messageArgument);
switch (arg) {
case kIOACPIMessageBrightnessUp:
clock_get_uptime(&now_abs);
self->dispatchKeyboardEventX(BRIGHTNESS_UP, true, now_abs);
clock_get_uptime(&now_abs);
self->dispatchKeyboardEventX(BRIGHTNESS_UP, false, now_abs);
DEBUG_LOG("%s %s ACPI brightness up\n", self->getName(), provider->getName());
info.adbKeyCode = BRIGHTNESS_UP;
info.eatKey = false;
info.goingDown = true;
clock_get_uptime(&info.time);
self->dispatchMessage(kPS2K_notifyKeystroke, &info);
// keyboard consume the message
if (info.eatKey) {
info.eatKey = false;
info.goingDown = false;
clock_get_uptime(&info.time);
self->dispatchMessage(kPS2K_notifyKeystroke, &info);
} else {
clock_get_uptime(&info.time);
self->dispatchKeyboardEventX(BRIGHTNESS_UP, true, info.time);
clock_get_uptime(&info.time);
self->dispatchKeyboardEventX(BRIGHTNESS_UP, false, info.time);
}
DBGLOG("brkeys", "%s ACPI brightness up\n", provider->getName());
break;

case kIOACPIMessageBrightnessDown:
clock_get_uptime(&now_abs);
self->dispatchKeyboardEventX(BRIGHTNESS_DOWN, true, now_abs);
clock_get_uptime(&now_abs);
self->dispatchKeyboardEventX(BRIGHTNESS_DOWN, false, now_abs);
DEBUG_LOG("%s %s ACPI brightness down\n", self->getName(), provider->getName());
info.adbKeyCode = BRIGHTNESS_DOWN;
info.eatKey = false;
info.goingDown = true;
clock_get_uptime(&info.time);
self->dispatchMessage(kPS2K_notifyKeystroke, &info);
// keyboard consume the message
if (info.eatKey) {
info.eatKey = false;
info.goingDown = false;
clock_get_uptime(&info.time);
self->dispatchMessage(kPS2K_notifyKeystroke, &info);
} else {
clock_get_uptime(&info.time);
self->dispatchKeyboardEventX(BRIGHTNESS_DOWN, true, info.time);
clock_get_uptime(&info.time);
self->dispatchKeyboardEventX(BRIGHTNESS_DOWN, false, info.time);
}
DBGLOG("brkeys", "%s ACPI brightness down", provider->getName());
break;

case kIOACPIMessageBrightnessCycle:
case kIOACPIMessageBrightnessZero:
case kIOACPIMessageBrightnessOff:
DEBUG_LOG("%s %s ACPI brightness operation 0x%02x not implemented\n", self->getName(), provider->getName(), *((UInt32 *) messageArgument));
DBGLOG("brkeys", "%s ACPI brightness operation 0x%02x not implemented", provider->getName(), *((UInt32 *) messageArgument));
return kIOReturnSuccess;

default:
DEBUG_LOG("%s %s unknown ACPI notification 0x%04x\n", self->getName(), provider->getName(), *((UInt32 *) messageArgument));
DBGLOG("brkeys", "%s unknown ACPI notification 0x%04x", provider->getName(), *((UInt32 *) messageArgument));
return kIOReturnSuccess;
}
if (!self->_panelNotified) {
self->_panelNotified = true;
self->setProperty(kBrightnessPanel, safeString(provider->getName()));
if (arg == kIOACPIMessageBrightnessUp || arg == kIOACPIMessageBrightnessDown)
self->setProperty(kBrightnessKey, info.eatKey);
}
} else {
DEBUG_LOG("%s %s received unknown kIOACPIMessageDeviceNotification\n", self->getName(), provider->getName());
DBGLOG("brkeys", "%s received unknown kIOACPIMessageDeviceNotification", provider->getName());
}
} else {
DEBUG_LOG("%s received %08X\n", provider->getName(), messageType);
DBGLOG("brkeys", "%s received %08X", provider->getName(), messageType);
}
return kIOReturnSuccess;
}

void BrightnessKeys::dispatchMessageGated(int* message, void* data)
{
OSCollectionIterator* i = OSCollectionIterator::withCollection(_notificationServices);

if (i) {
while (IOService* service = OSDynamicCast(IOService, i->getNextObject())) {
service->message(*message, this, data);
}
i->release();
}
}

void BrightnessKeys::dispatchMessage(int message, void* data)
{
if (_notificationServices->getCount() == 0) {
SYSLOG("brkeys", "No available notification consumer");
return;
}
commandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &BrightnessKeys::dispatchMessageGated), &message, data);
}

void BrightnessKeys::notificationHandlerGated(IOService *newService, IONotifier *notifier)
{
if (notifier == _publishNotify) {
DBGLOG("brkeys", "Notification consumer published: %s", safeString(newService->getName()));
_notificationServices->setObject(newService);
}

if (notifier == _terminateNotify) {
DBGLOG("brkeys", "Notification consumer terminated: %s", safeString(newService->getName()));
_notificationServices->removeObject(newService);
}
}

bool BrightnessKeys::notificationHandler(void *refCon, IOService *newService, IONotifier *notifier)
{
commandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &BrightnessKeys::notificationHandlerGated), newService, notifier);
return true;
}

UInt32 BrightnessKeys::interfaceID() { return NX_EVS_DEVICE_INTERFACE_ADB; }

UInt32 BrightnessKeys::maxKeyCodes() { return NX_NUMKEYCODES; }
Expand Down
35 changes: 24 additions & 11 deletions BrightnessKeys/BrightnessKeys.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <IOKit/IOService.h>
#include <IOKit/hidsystem/IOHIKeyboard.h>
#include <IOKit/acpi/IOACPIPlatformDevice.h>
#include <IOKit/IOCommandGate.h>
#include <IOKit/IODeviceTreeSupport.h>


Expand All @@ -31,23 +32,35 @@ class BrightnessKeys : public IOHIKeyboard {
OSDeclareDefaultStructors(BrightnessKeys)
private:
// ACPI support for panel brightness
IOACPIPlatformDevice * _panel;
IOACPIPlatformDevice * _panelFallback;
IOACPIPlatformDevice * _panelDiscrete;
bool _panelNotified;
bool _panelPrompt;
IONotifier * _panelNotifiers;
IONotifier * _panelNotifiersFallback;
IONotifier * _panelNotifiersDiscrete;

IOACPIPlatformDevice * _panel {nullptr};
IOACPIPlatformDevice * _panelFallback {nullptr};
IOACPIPlatformDevice * _panelDiscrete {nullptr};
bool _panelNotified {false};
IONotifier * _panelNotifiers {nullptr};
IONotifier * _panelNotifiersFallback {nullptr};
IONotifier * _panelNotifiersDiscrete {nullptr};

IOWorkLoop *workLoop {nullptr};
IOCommandGate *commandGate {nullptr};

IONotifier *_publishNotify {nullptr};
IONotifier *_terminateNotify {nullptr};
OSSet *_notificationServices {nullptr};
const OSSymbol *_deliverNotification {nullptr};

void dispatchMessageGated(int* message, void* data);
bool notificationHandler(void * refCon, IOService * newService, IONotifier * notifier);
void notificationHandlerGated(IOService * newService, IONotifier * notifier);

public:
IORegistryEntry* getDeviceByAddress(IORegistryEntry *parent, UInt64 address, UInt64 mask = 0xFFFFFFFF);
void getBrightnessPanel();
static IOReturn _panelNotification(void *target, void *refCon, UInt32 messageType, IOService *provider, void *messageArgument, vm_size_t argSize);
inline void dispatchKeyboardEventX(unsigned int keyCode, bool goingDown, uint64_t time)
{ dispatchKeyboardEvent(keyCode, goingDown, *(AbsoluteTime*)&time); }

virtual bool init() override;

void dispatchMessage(int message, void* data);

virtual bool start(IOService *provider) override;
virtual void stop(IOService *provider) override;

Expand Down