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