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