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