1/* 2 * 3 * @APPLE_LICENSE_HEADER_START@ 4 * 5 * Copyright (c) 1999-2009 Apple Computer, Inc. All Rights Reserved. 6 * 7 * This file contains Original Code and/or Modifications of Original Code 8 * as defined in and that are subject to the Apple Public Source License 9 * Version 2.0 (the 'License'). You may not use this file except in 10 * compliance with the License. Please obtain a copy of the License at 11 * http://www.opensource.apple.com/apsl/ and read it before using this 12 * file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 * Please see the License for the specific language governing rights and 20 * limitations under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24 25#include <IOKit/IOLib.h> 26#include "AppleEmbeddedKeyboard.h" 27#include "AppleHIDUsageTables.h" 28#include "IOHIDUsageTables.h" 29#include "IOHIDKeyboard.h" 30#include "IOHIDPrivateKeys.h" 31#include "IOLLEvent.h" 32 33#define super IOHIDEventDriver 34 35OSDefineMetaClassAndStructors( AppleEmbeddedKeyboard, IOHIDEventDriver ) 36 37//==================================================================================================== 38// AppleEmbeddedKeyboard::init 39//==================================================================================================== 40bool AppleEmbeddedKeyboard::init(OSDictionary * properties) 41{ 42 if ( !super::init(properties) ) 43 return false; 44 45 bzero(_secondaryKeys, sizeof(SecondaryKey)*255); 46 47 return true; 48} 49 50//==================================================================================================== 51// AppleEmbeddedKeyboard::free 52//==================================================================================================== 53void AppleEmbeddedKeyboard::free() 54{ 55 if ( _keyboardMap ) 56 _keyboardMap->release(); 57 58 super::free(); 59} 60 61//==================================================================================================== 62// AppleEmbeddedKeyboard::handleStart 63//==================================================================================================== 64bool AppleEmbeddedKeyboard::handleStart( IOService * provider ) 65{ 66 setProperty(kIOHIDAppleVendorSupported, kOSBooleanTrue); 67 68 if (!super::handleStart(provider)) 69 return false; 70 71 // RY: The fn key is reported in the 8th byte of the keyboard report. 72 // This byte is part of the normal keyboard boot protocol report. 73 // Unfortunately, because of this, a keyboard roll over will trick 74 // the driver into thinking that the fn key is down. 75 findKeyboardRollOverElement(getReportElements()); 76 77 parseSecondaryUsages(); 78 79 _keyboardMap = OSDynamicCast(OSDictionary, copyProperty(kKeyboardUsageMapKey)); 80 setProperty(kIOHIDFKeyModeKey, _fKeyMode, sizeof(_fKeyMode)); 81 82 return true; 83} 84 85 86//==================================================================================================== 87// AppleEmbeddedKeyboard::setElementValue 88//==================================================================================================== 89void AppleEmbeddedKeyboard::setElementValue ( 90 UInt32 usagePage, 91 UInt32 usage, 92 UInt32 value ) 93{ 94 if ((usagePage == kHIDPage_LEDs) && (usage == kHIDUsage_LED_NumLock)) 95 _numLockDown = (value != 0); 96 97 super::setElementValue(usagePage, usage, value); 98} 99 100//==================================================================================================== 101// AppleEmbeddedKeyboard::dispatchKeyboardEvent 102//==================================================================================================== 103void AppleEmbeddedKeyboard::dispatchKeyboardEvent( 104 AbsoluteTime timeStamp, 105 UInt32 usagePage, 106 UInt32 usage, 107 UInt32 value, 108 IOOptionBits options) 109{ 110 filterKeyboardUsage(&usagePage, &usage, value); 111 112 if ( (( usagePage == kHIDPage_AppleVendorTopCase ) && ( usage == kHIDUsage_AV_TopCase_KeyboardFn )) || 113 (( usagePage == kHIDPage_AppleVendorKeyboard ) && ( usage == kHIDUsage_AppleVendorKeyboard_Function )) ) 114 { 115 if (_keyboardRollOverElement) 116 { 117 AbsoluteTime rolloverTS = _keyboardRollOverElement->getTimeStamp(); 118 119 if ((CMP_ABSOLUTETIME(&rolloverTS, &timeStamp) == 0) && 120 ((_keyboardRollOverElement->getValue() && value && !_fnKeyDownPhysical) || (_fnKeyDownPhysical == value))) 121 return; 122 } 123 124 _fnKeyDownPhysical = (value != 0); 125 } 126 else if ( usagePage == kHIDPage_KeyboardOrKeypad ) 127 { 128 if (!filterSecondaryFnFunctionUsage(&usagePage, &usage, (value!=0)) 129 && !filterSecondaryFnKeyboardUsage(&usagePage, &usage, (value!=0)) 130 && filterSecondaryNumLockKeyboardUsage(&usagePage, &usage, (value!=0))) 131 return; 132 } 133 134 super::dispatchKeyboardEvent(timeStamp, usagePage, usage, value, options); 135 136#if !TARGET_OS_EMBEDDED 137 _fnKeyDownVirtual = _keyboardNub ? (_keyboardNub->eventFlags() & NX_SECONDARYFNMASK) : _fnKeyDownPhysical; 138#else 139 _fnKeyDownVirtual = _fnKeyDownPhysical; 140#endif 141} 142 143 144/* vtn3: rdar://7045478 removed for readability 145#define SHOULD_SWAP_FN_FUNCTION_KEY(key, down) \ 146 ((_secondaryKeys[key].bits & kSecondaryKeyFnFunction) && \ 147 (!( _fnKeyDownPhysical ^ _fKeyMode ) || (!down && \ 148 (_secondaryKeys[key].swapping & kSecondaryKeyFnFunction)))) 149 150#define SHOULD_SWAP_FN_KEYBOARD_KEY(key, down) \ 151 ((_secondaryKeys[key].bits & kSecondaryKeyFnKeyboard) && \ 152 (_fnKeyDownVirtual || (!down && \ 153 (_secondaryKeys[key].swapping & kSecondaryKeyFnKeyboard)))) 154 155#define SHOULD_SWAP_NUM_LOCK_KEY(key, down) \ 156 ((_numLockDown || ( !down && \ 157 (_secondaryKeys[key].swapping & kSecondaryKeyNumLockKeyboard)))) 158 */ 159 160//==================================================================================================== 161// AppleEmbeddedKeyboard::filterSecondaryFnFunctionUsage 162//==================================================================================================== 163bool AppleEmbeddedKeyboard::filterSecondaryFnFunctionUsage( 164 UInt32 * usagePage, 165 UInt32 * usage, 166 bool down) 167{ 168 // vtn3: rdar://7045478 { 169 // This takes the place of SHOULD_SWAP_FN_FUNCTION_KEY 170 // Only remap keys that have a remapping 171 if (!(_secondaryKeys[*usage].bits & kSecondaryKeyFnFunction)) 172 return false; 173 174 // On a down, we want to remap iff the Fn key is down. 175 if (down && ( _fnKeyDownPhysical ^ _fKeyMode )) 176 return false; 177 178 // On an up we want to remap iff the key was remapped for the down. We do not 179 // care if the Fn key is down. 180 if (!down && !(_secondaryKeys[*usage].swapping & kSecondaryKeyFnFunction)) 181 return false; 182 // end rdar://7045478 } 183 184#if !TARGET_OS_EMBEDDED 185 if ((*usagePage == kHIDPage_KeyboardOrKeypad) && (*usage == kHIDUsage_KeyboardF5)) { 186 UInt32 flags = _keyboardNub ? _keyboardNub->eventFlags() : 0; 187 if (flags & (NX_COMMANDMASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK)) { 188 // <rdar://problem/6305898> Enhancement: Make Cmd+Fn+Key == Cmd+Key 189 return false; 190 } 191 } 192#endif 193 194 if (down) 195 _secondaryKeys[*usage].swapping |= kSecondaryKeyFnFunction; 196 else 197 _secondaryKeys[*usage].swapping = 0; 198 199 *usagePage = _secondaryKeys[*usage].fnFunctionUsagePage; 200 *usage = _secondaryKeys[*usage].fnFunctionUsage; 201 202 return true; 203} 204 205//==================================================================================================== 206// AppleEmbeddedKeyboard::filterSecondaryFnKeyboardUsage 207//==================================================================================================== 208bool AppleEmbeddedKeyboard::filterSecondaryFnKeyboardUsage( 209 UInt32 * usagePage, 210 UInt32 * usage, 211 bool down) 212{ 213 // vtn3: rdar://7045478 { 214 // This takes the place of SHOULD_SWAP_FN_KEYBOARD_KEY 215 // Only remap keys that have a remapping 216 if (!(_secondaryKeys[*usage].bits & kSecondaryKeyFnKeyboard)) 217 return false; 218 219 // On a down, we want to remap iff the Fn key is down. 220 if (down && !_fnKeyDownVirtual) 221 return false; 222 223 // On an up we want to remap iff the key was remapped for the down. We do not 224 // care if the Fn key is down. 225 if (!down && !(_secondaryKeys[*usage].swapping & kSecondaryKeyFnKeyboard)) 226 return false; 227 228 // end rdar://7045478 } 229 230 if (down) 231 _secondaryKeys[*usage].swapping |= kSecondaryKeyFnKeyboard; 232 else 233 _secondaryKeys[*usage].swapping = 0; 234 235 *usagePage = _secondaryKeys[*usage].fnKeyboardUsagePage; 236 *usage = _secondaryKeys[*usage].fnKeyboardUsage; 237 238 return false; 239} 240 241//==================================================================================================== 242// AppleEmbeddedKeyboard::filterSecondaryNumLockKeyboardUsage 243//==================================================================================================== 244bool AppleEmbeddedKeyboard::filterSecondaryNumLockKeyboardUsage( 245 UInt32 * usagePage, 246 UInt32 * usage, 247 bool down) 248{ 249 // vtn3: rdar://7045478 { 250 // This takes the place of SHOULD_SWAP_NUM_LOCK_KEY 251 252 // On a down, we want to remap iff the Num Lock key is down. 253 if (down && !_numLockDown) 254 return false; 255 256 // On an up we want to remap iff the key was remapped for the down. We do not 257 // care if the Num Lock key is down. 258 if (!down && !(_secondaryKeys[*usage].swapping & kSecondaryKeyNumLockKeyboard)) 259 return false; 260 261 // If the key is not a swapped numpad key, consume it 262 if (_secondaryKeys[*usage].bits & kSecondaryKeyNumLockKeyboard) 263 { 264 if (down) 265 _secondaryKeys[*usage].swapping |= kSecondaryKeyNumLockKeyboard; 266 else 267 _secondaryKeys[*usage].swapping = 0; 268 269 *usagePage = _secondaryKeys[*usage].numLockKeyboardUsagePage; 270 *usage = _secondaryKeys[*usage].numLockKeyboardUsage; 271 } 272 else if ( down ) 273 return true; 274 275 return false; 276} 277 278//==================================================================================================== 279// AppleEmbeddedKeyboard::filterKeyboardUsage 280//==================================================================================================== 281bool AppleEmbeddedKeyboard::filterKeyboardUsage(UInt32 * usagePage, 282 UInt32 * usage, 283 bool down __unused) 284{ 285 char key[32]; 286 287 bzero(key, sizeof(key)); 288 snprintf(key, sizeof(key), "0x%04x%04x", (uint16_t)*usagePage, (uint16_t)*usage); 289 290 if ( _keyboardMap ) { 291 OSNumber * map = OSDynamicCast(OSNumber, _keyboardMap->getObject(key)); 292 293 if ( map ) { 294 *usagePage = (map->unsigned32BitValue()>>16) & 0xffff; 295 *usage = map->unsigned32BitValue()&0xffff; 296 297 } 298 } 299 300 return false; 301} 302 303//==================================================================================================== 304// AppleEmbeddedKeyboard::findKeyboardRollOverElement 305//==================================================================================================== 306void AppleEmbeddedKeyboard::findKeyboardRollOverElement(OSArray * reportElements) 307{ 308 IOHIDElement * element; 309 UInt32 count; 310 311 if (!reportElements) 312 return; 313 314 count = reportElements->getCount(); 315 316 for (UInt32 i=0; i<count; i++) 317 { 318 element = (IOHIDElement *) reportElements->getObject(i); 319 320 if (element && (element->getUsagePage() == kHIDPage_KeyboardOrKeypad ) && 321 (element->getUsage() == kHIDUsage_KeyboardErrorRollOver)) 322 { 323 _keyboardRollOverElement = element; 324 return; 325 } 326 } 327} 328 329//==================================================================================================== 330// AppleEmbeddedKeyboard::parseSecondaryUsages 331//==================================================================================================== 332void AppleEmbeddedKeyboard::parseSecondaryUsages() 333{ 334 OSString * mappingString; 335 char * str; 336 UInt32 index, value; 337 338#define DECODE_MAP(type,key,bit) \ 339 do { \ 340 OSObject *obj = copyProperty(key); \ 341 mappingString = OSDynamicCast(OSString,obj); \ 342 if (mappingString) { \ 343 str = (char *)mappingString->getCStringNoCopy(); \ 344 while ( str && (*str != '\0')) { \ 345 index = strtoul(str, &str, 16) & 0xff; \ 346 while ((*str!='\0')&&((*str < '0')||(*str > '9'))) { str ++; } \ 347 value = strtoul(str, &str, 16); \ 348 while ((*str!='\0')&&((*str < '0')||(*str > '9'))) { str ++; } \ 349 _secondaryKeys[index].type##UsagePage = (value >> 16) & 0xffff; \ 350 _secondaryKeys[index].type##Usage = value & 0xffff; \ 351 _secondaryKeys[index].bits |= bit; \ 352 } \ 353 } \ 354 if (obj) obj->release(); \ 355 } while (0) 356 357 DECODE_MAP(numLockKeyboard, kNumLockKeyboardUsageMapKey, kSecondaryKeyNumLockKeyboard); 358 359 DECODE_MAP(fnKeyboard, kFnKeyboardUsageMapKey, kSecondaryKeyFnKeyboard); 360 361 DECODE_MAP(fnFunction, kFnFunctionUsageMapKey, kSecondaryKeyFnFunction); 362 363 if ( getProperty(kNumLockKeyboardUsageMapKey) ) { 364 _virtualMouseKeysSupport = TRUE; 365 for (index=0; index<255; index++) { 366 if ( ( _secondaryKeys[index].bits & kSecondaryKeyFnFunction ) && 367 ( _secondaryKeys[index].fnFunctionUsagePage == kHIDPage_KeyboardOrKeypad ) && 368 ( _secondaryKeys[index].fnFunctionUsage == kHIDUsage_KeyboardLockingNumLock ) ) { 369 370 _virtualMouseKeysSupport = FALSE; 371 break; 372 } 373 } 374 } else { 375 _virtualMouseKeysSupport = FALSE; 376 } 377 378 setProperty(kIOHIDMouseKeysEnablesVirtualNumPadKey, _virtualMouseKeysSupport); 379} 380 381 382//==================================================================================================== 383// AppleEmbeddedKeyboard::setSystemProperties 384//==================================================================================================== 385IOReturn AppleEmbeddedKeyboard::setSystemProperties( OSDictionary * properties ) 386{ 387 OSNumber * number; 388 OSString * string; 389 bool parseSecondaries = false; 390 391 if ((number = OSDynamicCast(OSNumber, properties->getObject(kIOHIDFKeyModeKey)))) 392 { 393 _fKeyMode = number->unsigned32BitValue(); 394 setProperty(kIOHIDFKeyModeKey, number); 395 } 396 397 if (_virtualMouseKeysSupport && ((number = OSDynamicCast(OSNumber, properties->getObject(kIOHIDMouseKeysOnKey))))) 398 { 399 _numLockDown = number->unsigned32BitValue(); 400 } 401 402 if ((string = OSDynamicCast(OSString, properties->getObject(kFnFunctionUsageMapKey)))) { 403 setProperty(kFnFunctionUsageMapKey, string); 404 parseSecondaries = true; 405 } 406 407 if ((string = OSDynamicCast(OSString, properties->getObject(kFnKeyboardUsageMapKey)))) { 408 setProperty(kFnKeyboardUsageMapKey, string); 409 parseSecondaries = true; 410 } 411 412 if ((string = OSDynamicCast(OSString, properties->getObject(kNumLockKeyboardUsageMapKey)))) { 413 setProperty(kNumLockKeyboardUsageMapKey, string); 414 parseSecondaries = true; 415 } 416 417 if (parseSecondaries) { 418 parseSecondaryUsages(); 419 } 420 421 return super::setSystemProperties(properties); 422} 423 424//==================================================================================================== 425