1/*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 1999-2009 Apple Computer, Inc.	 All Rights Reserved.
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*	Copyright (c) 1992 NeXT Computer, Inc.	All rights reserved.
24 *
25 * KeyMap.m - Generic keymap string parser and keycode translator.
26 *
27 * HISTORY
28 * 19 June 1992	   Mike Paquette at NeXT
29 *		Created.
30 * 5  Aug 1993	  Erik Kay at NeXT
31 *	minor API cleanup
32 * 11 Nov 1993	  Erik Kay at NeXT
33 *	fix to allow prevent long sequences from overflowing the event queue
34 * 12 Nov 1998	  Dan Markarian at Apple
35 *		major cleanup of public API's; converted to C++
36 */
37
38#include <sys/systm.h>
39
40#include <IOKit/assert.h>
41#include <IOKit/IOLib.h>
42#include <IOKit/IODeviceTreeSupport.h>
43#include <IOKit/hidsystem/IOLLEvent.h>
44#include <IOKit/hidsystem/IOHIKeyboard.h>
45#include <IOKit/hidsystem/IOHIKeyboardMapper.h>
46#include <IOKit/hidsystem/IOHIDParameter.h>
47#include <IOKit/hidsystem/IOHIDSystem.h>
48#include <libkern/OSByteOrder.h>
49#include "IOHIDKeyboardDevice.h"
50#include "IOHIDevicePrivateKeys.h"
51#include "IOHIDFamilyPrivate.h"
52
53// Define expansion data here
54#define _f12Eject_State				_reserved->f12Eject_State
55#define _eject_Delay_MS				_reserved->eject_Delay_MS
56#define _ejectTimerEventSource			_reserved->ejectTimerEventSource
57#define _cached_KeyBits						_reserved->cached_KeyBits
58#define _stickyKeys_StuckModifiers			_reserved->stickyKeys_StuckModifiers
59#define _stickyKeysMouseClickEventSource	_reserved->stickyKeysMouseClickEventSource
60#define _stickyKeysSetFnStateEventSource	_reserved->stickyKeysSetFnStateEventSource
61#define _offFnParamDict				_reserved->offFnParamDict
62#define _onFnParamDict				_reserved->onFnParamDict
63#define _slowKeys_State				_reserved->slowKeys_State
64#define _slowKeys_Delay_MS			_reserved->slowKeys_Delay_MS
65#define _slowKeysTimerEventSource		_reserved->slowKeysTimerEventSource
66#define _slowKeys_Aborted_Key			_reserved->slowKeys_Aborted_Key
67#define _slowKeys_Current_Key			_reserved->slowKeys_Current_Key
68#define _specialKeyModifierFlags		_reserved->specialKeyModifierFlags
69#define _supportsF12Eject			_reserved->supportsF12Eject
70#define _modifierSwap_Modifiers		_reserved->modifierSwap_Modifiers
71#define _cachedAlphaLockModDefs		_reserved->cachedAlphaLockModDefs
72
73#define super OSObject
74OSDefineMetaClassAndStructors(IOHIKeyboardMapper, OSObject);
75
76// sticky keys private state flags
77enum
78{
79	kState_OptionActivates_Flag = 0x0010,	// the 'on' gesture (5 options) will activate mouse keys
80	kState_ClearHeldKeysFirst	= 0x0100,	// when set, we should clear all held keys
81												// this is a hack we are using since we
82												// cannot post key up events when our
83												// entry point is not a key event
84
85	kState_PrefFnKeyStateOn					= 0x0200,
86	kState_StickyFnKeyStateOn				= 0x0400,
87	kState_MouseKeyStateOn					= 0x0800,
88	kState_StickyFnKeyStateChangePending	= 0x1000,
89
90};
91
92
93
94// delay filter private state flags
95enum
96{
97	kState_Aborted_Flag		= 0x0200,
98	kState_In_Progess_Flag	= 0x0400,
99	kState_Is_Repeat_Flag	= 0x0800,
100};
101
102// ADB Key code for F12
103#define kADB_KEYBOARD_F12 0x6f
104
105// Shortcut for post slow key translation
106#define postSlowKeyTranslateKeyCode(owner,key,keyDown,keyBits)	\
107	if (!owner->f12EjectFilterKey(key, keyDown, keyBits))	\
108		if (!owner->stickyKeysFilterKey(key, keyDown, keyBits)) \
109			owner->rawTranslateKeyCode(key, keyDown, keyBits);
110
111
112// Shortcut for determining if we are interested in this modifier
113#define modifierOfInterest(keyBits) \
114			((keyBits & NX_MODMASK) && \
115			((((keyBits & NX_WHICHMODMASK) >= NX_MODIFIERKEY_SHIFT) && \
116			((keyBits & NX_WHICHMODMASK) <= NX_MODIFIERKEY_COMMAND)) || \
117			(((keyBits & NX_WHICHMODMASK) >= NX_MODIFIERKEY_RSHIFT) && \
118			((keyBits & NX_WHICHMODMASK) <= NX_MODIFIERKEY_LAST_KEY)) || \
119			((keyBits & NX_WHICHMODMASK) == NX_MODIFIERKEY_SECONDARYFN)))
120
121#define mouseKey(keyBits) \
122			((keyBits & NX_MODMASK) && \
123			 ((keyBits & NX_WHICHMODMASK) == NX_MODIFIERKEY_NUMERICPAD))
124
125#define mouseKeyToIgnore(keyBits, key) \
126			( mouseKey(keyBits) && \
127			 (((key >= 0x52) && (key <= 0x56)) || \
128			 ((key >= 0x58) && (key <= 0x5c))) )
129
130#define convertToLeftModBit(modBit) \
131		modBit -= ((modBit >= NX_MODIFIERKEY_RSHIFT) && \
132					(modBit <= NX_MODIFIERKEY_LAST_KEY)) ? 8 : 0;
133
134static UInt32 DeviceModifierMasks[NX_NUMMODIFIERS] =
135{
136  /* NX_MODIFIERKEY_ALPHALOCK */	0,
137  /* NX_MODIFIERKEY_SHIFT */		NX_DEVICELSHIFTKEYMASK,
138  /* NX_MODIFIERKEY_CONTROL */		NX_DEVICELCTLKEYMASK,
139  /* NX_MODIFIERKEY_ALTERNATE */	NX_DEVICELALTKEYMASK,
140  /* NX_MODIFIERKEY_COMMAND */		NX_DEVICELCMDKEYMASK,
141  /* NX_MODIFIERKEY_NUMERICPAD */	0,
142  /* NX_MODIFIERKEY_HELP */		0,
143  /* NX_MODIFIERKEY_SECONDARYFN */	0,
144  /* NX_MODIFIERKEY_NUMLOCK */		0,
145  /* NX_MODIFIERKEY_RSHIFT */		NX_DEVICERSHIFTKEYMASK,
146  /* NX_MODIFIERKEY_RCONTROL */		NX_DEVICERCTLKEYMASK,
147  /* NX_MODIFIERKEY_RALTERNATE */	NX_DEVICERALTKEYMASK,
148  /* NX_MODIFIERKEY_RCOMMAND */		NX_DEVICERCMDKEYMASK,
149  /* NX_MODIFIERKEY_ALPHALOCK_STATELESS */  NX_DEVICE_ALPHASHIFT_STATELESS_MASK,
150  0,
151  0
152};
153
154// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
155
156IOHIKeyboardMapper * IOHIKeyboardMapper::keyboardMapper(
157										IOHIKeyboard * delegate,
158										const UInt8 *  mapping,
159										UInt32		   mappingLength,
160										bool		   mappingShouldBeFreed )
161{
162	IOHIKeyboardMapper * me = new IOHIKeyboardMapper;
163
164	if (me && !me->init(delegate, mapping, mappingLength, mappingShouldBeFreed))
165	{
166		me->release();
167		return 0;
168	}
169
170	return me;
171}
172
173// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
174
175/*
176 * Common KeyMap initialization
177 */
178bool IOHIKeyboardMapper::init(	IOHIKeyboard *delegate,
179								const UInt8 *map,
180								UInt32 mappingLen,
181								bool mappingShouldBeFreed )
182{
183	if (!super::init())	 return false;
184
185	_delegate				  = delegate;
186
187	if (!parseKeyMapping(map, mappingLen, &_parsedMapping))	return false;
188
189	_mappingShouldBeFreed		= mappingShouldBeFreed;
190	_parsedMapping.mapping		= map;
191	_parsedMapping.mappingLen	= mappingLen;
192
193	_hidSystem					= NULL;
194	_stateDirty					= false;
195
196	_reserved = IONew(ExpansionData, 1);
197    bzero(_reserved, sizeof(ExpansionData));
198
199	_ejectTimerEventSource		= 0;
200
201	_f12Eject_State			= 0;
202
203	_eject_Delay_MS			= kEjectF12DelayMS;
204
205	_slowKeys_State			= 0;
206
207	_slowKeys_Delay_MS		= 0;
208
209	_slowKeysTimerEventSource	= 0;
210
211	_specialKeyModifierFlags	= 0;
212
213	_supportsF12Eject		= 0;
214
215	_cached_KeyBits			= 0;
216
217	_cachedAlphaLockModDefs = 0;
218
219	// If there are right hand modifiers defined, set a property
220	if (_delegate && (_parsedMapping.maxMod > 0))
221	{
222
223		if ( _delegate->doesKeyLock(NX_KEYTYPE_CAPS_LOCK) )
224		{
225			_delegate->setProperty( kIOHIDKeyboardCapsLockDoesLockKey, kOSBooleanTrue);
226			_cachedAlphaLockModDefs = _parsedMapping.modDefs[NX_MODIFIERKEY_ALPHALOCK];
227		}
228		else
229		{
230			_delegate->setProperty( kIOHIDKeyboardCapsLockDoesLockKey, kOSBooleanFalse);
231		}
232
233		UInt32 supportedModifiers = 0;
234		OSNumber * number = 0;
235
236		number = (OSNumber *)_delegate->copyProperty(kIOHIDKeyboardSupportedModifiersKey);
237
238		if (number) supportedModifiers = number->unsigned32BitValue();
239		OSSafeReleaseNULL(number);
240
241		for (int mod=0; mod<NX_NUMMODIFIERS; mod++)
242		{
243			if (_parsedMapping.modDefs[mod])
244			{
245				if (DeviceModifierMasks[mod])
246					supportedModifiers |= DeviceModifierMasks[mod];
247				else
248					supportedModifiers |= 1<<(mod+16);
249			}
250
251			// RY: Init modifier swap while we are at it
252			_modifierSwap_Modifiers[mod] = mod;
253		}
254		_delegate->setProperty( kIOHIDKeyboardSupportedModifiersKey, supportedModifiers, 32 );
255
256		if ( (supportedModifiers & NX_DEVICERSHIFTKEYMASK) ||
257			 (supportedModifiers & NX_DEVICERCTLKEYMASK) ||
258			 (supportedModifiers & NX_DEVICERALTKEYMASK) ||
259			 (supportedModifiers & NX_DEVICERCMDKEYMASK) )
260		{
261			_delegate->setProperty("HIDKeyboardRightModifierSupport", kOSBooleanTrue);
262		}
263	}
264
265	if (_parsedMapping.numDefs && _delegate)
266	{
267		_delegate->setProperty("HIDKeyboardKeysDefined", kOSBooleanTrue);
268
269		// If keys are defined, check the device type to determine
270		// if we should support F12 eject.
271		if ((_delegate->interfaceID() == NX_EVS_DEVICE_INTERFACE_ADB) &&
272			(((_delegate->deviceType() >= 0xc3) && (_delegate->deviceType() <= 0xc9)) ||
273			 ((_delegate->deviceType() >= 0x28) && (_delegate->deviceType() <= 0x2a)) ||
274			 (                                     (_delegate->deviceType() <= 0x1e))))
275		{
276			_supportsF12Eject = true;
277			_delegate->setProperty( kIOHIDKeyboardSupportsF12EjectKey,
278									_supportsF12Eject);
279		}
280	}
281
282	if ( !_delegate->doesKeyLock(NX_KEYTYPE_CAPS_LOCK) )
283	{
284		UInt32 myFlags = _delegate->deviceFlags();
285
286		if ( _delegate->alphaLock() )
287		{
288			_specialKeyModifierFlags	|= NX_ALPHASHIFTMASK;
289			myFlags						|= NX_ALPHASHIFTMASK;
290
291			_delegate->IOHIKeyboard::setDeviceFlags(myFlags);
292		}
293		else
294		{
295			_specialKeyModifierFlags	&= ~NX_ALPHASHIFTMASK;
296			myFlags						&= ~NX_ALPHASHIFTMASK;
297
298			_delegate->IOHIKeyboard::setDeviceFlags(myFlags);
299		}
300	}
301
302	return stickyKeysinit();
303}
304
305// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
306void IOHIKeyboardMapper::free()
307{
308    if (!_parsedMapping.mapping || !_parsedMapping.mappingLen)
309        return;
310
311    stickyKeysfree();
312
313    if (_reserved) {
314        if (_ejectTimerEventSource) {
315            _ejectTimerEventSource->cancelTimeout();
316
317            IOWorkLoop * workLoop = _hidSystem->getWorkLoop();
318
319            if ( workLoop )
320                workLoop->removeEventSource( _ejectTimerEventSource );
321
322            _ejectTimerEventSource->release();
323            _ejectTimerEventSource = 0;
324        }
325
326        if (_slowKeysTimerEventSource) {
327            _slowKeysTimerEventSource->cancelTimeout();
328
329            IOWorkLoop * workLoop = _hidSystem->getWorkLoop();
330
331            if ( workLoop )
332                workLoop->removeEventSource( _slowKeysTimerEventSource );
333
334            _slowKeysTimerEventSource->release();
335            _slowKeysTimerEventSource = 0;
336        }
337
338        IODelete(_reserved, ExpansionData, 1);
339    }
340
341    if (_mappingShouldBeFreed)
342        IOFree((void *)_parsedMapping.mapping, _parsedMapping.mappingLen);
343
344    super::free();
345}
346
347// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
348
349const UInt8 * IOHIKeyboardMapper::mapping()
350{
351	return (const UInt8 *)_parsedMapping.mapping;
352}
353
354// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
355
356UInt32 IOHIKeyboardMapper::mappingLength()
357{
358  return _parsedMapping.mappingLen;
359}
360
361// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
362
363bool IOHIKeyboardMapper::serialize(OSSerialize *s) const
364{
365	OSData * data;
366	bool ok;
367
368	if (s->previouslySerialized(this)) return true;
369
370	data = OSData::withBytesNoCopy( (void *) _parsedMapping.mapping, _parsedMapping.mappingLen );
371	if (data) {
372	ok = data->serialize(s);
373	data->release();
374	} else
375	ok = false;
376
377	return( ok );
378}
379
380// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
381
382//
383// Perform the mapping of 'key' moving in the specified direction
384// into events.
385//
386
387void IOHIKeyboardMapper::translateKeyCode(UInt8		   key,
388										  bool		   keyDown,
389										  kbdBitVector keyBits)
390{
391	if ( !_cached_KeyBits )
392		_cached_KeyBits = keyBits;
393
394	if (!modifierSwapFilterKey(&key))
395		// SlowKeys filter, if slowKeysFilterKey returns true,
396		// this key is already processed
397		if (!slowKeysFilterKey(key, keyDown, keyBits))
398			// Filter out F12 to check for an eject
399			if (!f12EjectFilterKey(key, keyDown, keyBits))
400				// Stickykeys filter, if stickyKeysFilterKey returns true,
401				// this key is already processed
402				if (!stickyKeysFilterKey(key, keyDown, keyBits))
403						// otherwise, call the original raw translate key code
404						rawTranslateKeyCode(key, keyDown, keyBits);
405}
406
407
408// rawTranslateKeyCode is the original translateKeyCode function,
409//	prior to the Stickykeys feature
410//
411// Perform the mapping of 'key' moving in the specified direction
412// into events.
413//
414void IOHIKeyboardMapper::rawTranslateKeyCode(UInt8 key,
415											bool keyDown,
416											kbdBitVector keyBits)
417{
418	unsigned char thisBits = _parsedMapping.keyBits[key];
419
420	/* do mod bit update and char generation in useful order */
421	if (keyDown)
422	{
423		EVK_KEYDOWN(key, keyBits);
424
425		if (thisBits & NX_MODMASK)		doModCalc(key, keyBits);
426		if (thisBits & NX_CHARGENMASK)	doCharGen(key, keyDown);
427	}
428	else
429	{
430		EVK_KEYUP(key, keyBits);
431		if (thisBits & NX_CHARGENMASK)	doCharGen(key, keyDown);
432		if (thisBits & NX_MODMASK)		doModCalc(key, keyBits);
433	}
434
435	// Fix JIS localization. We are here because the JIS keys Yen, Ro, Eisu,
436	// Kana, and "," are not matched in _parsedMapping.keyBits[] above even
437	// though the keyboard drivers are sending the correct scan codes.
438	// The check for interfaceID() below makes sure both ADB and USB works.
439	// This fix has been tested with AppKit and Carbon for Kodiak 1H
440	if( 0 == (thisBits & (NX_MODMASK | NX_CHARGENMASK)))
441		if (_delegate->interfaceID() == NX_EVS_DEVICE_INTERFACE_ADB)
442	{
443			unsigned charCode=0;
444
445			switch (key) {
446			case 0x5F:	// numpad ',' using raw ADB scan code
447				charCode = ',';
448				break;
449			case 0x5E:	//ro
450				charCode = '_';
451				break;
452			case 0x5d:	//Yen
453				charCode = '\\';
454				break;
455			case 0x0a:
456				charCode = 0xa7;
457				break;
458			case 0x66:	// eisu
459			case 0x68:	// kana
460			default:
461				// do nothing. AppKit has fix in 1H
462				break;
463			}
464			/* Post the keyboard event */
465			_delegate->keyboardEvent(keyDown ? NX_KEYDOWN : NX_KEYUP,
466				/* flags */				_delegate->eventFlags(),
467				/* keyCode */			key,
468				/* charCode */			charCode,
469				/* charSet */			0,	//0 is adequate for JIS
470				/* originalCharCode */	0,
471				/* originalCharSet */	0);
472	}
473
474#ifdef OMITPENDINGKEYCAPS
475	unsigned char *	bp;
476
477	// Make KeyCaps.app see the caps lock
478	if (key == _parsedMapping.specialKeys[NX_KEYTYPE_CAPS_LOCK])	//ADB caps lock 0x39
479	{
480		if (_delegate->alphaLock() == keyDown)
481		//This logic is needed for non-locking USB caps lock
482		{
483		_delegate->keyboardEvent(keyDown ? NX_KEYDOWN : NX_KEYUP,
484			_delegate->eventFlags(), key, 0, 0, 0, 0);
485		}
486	}
487
488		//Find scan code corresponding to PowerBook fn key (0x3f in ADB)
489		bp = _parsedMapping.modDefs[NX_MODIFIERKEY_SECONDARYFN]; //7th array entry
490		if (bp)
491		{
492		bp++; //now points to actual ADB scan code
493		if (key == *bp ) //ADB fn key should be 0x3f here
494		{
495			_delegate->keyboardEvent(keyDown ? NX_KEYDOWN : NX_KEYUP,
496			_delegate->eventFlags(), key, 0, 0, 0, 0);
497		}
498		}
499#endif
500}
501
502// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
503
504//
505// Support goop for parseKeyMapping.  These routines are
506// used to walk through the keymapping string.	The string
507// may be composed of bytes or shorts.	If using shorts, it
508// MUST always be aligned to use short boundries.
509//
510typedef struct {
511	unsigned const char *bp;
512	unsigned const char *endPtr;
513	int shorts;
514} NewMappingData;
515
516static inline unsigned int NextNum(NewMappingData *nmd)
517{
518	if (nmd->bp >= nmd->endPtr)
519		return(0);
520	if (nmd->shorts) {
521        unsigned short tmp = *((unsigned short *)nmd->bp);
522        nmd->bp += 2;
523		return OSSwapBigToHostInt16(tmp);
524}
525	else {
526        unsigned char tmp = *(nmd->bp);
527        nmd->bp++;
528        return tmp;
529    }
530}
531
532//
533// Perform the actual parsing operation on a keymap.  Returns false on failure.
534//
535
536bool IOHIKeyboardMapper::parseKeyMapping(const UInt8 *		  map,
537										 UInt32				  mappingLen,
538									 NXParsedKeyMapping * parsedMapping) const
539{
540	NewMappingData nmd;
541	int i, j, k, l, n;
542	unsigned int m;
543	int keyMask, numMods;
544	int maxSeqNum = -1;
545		unsigned char *			bp;
546
547
548	/* Initialize the new map. */
549	bzero( parsedMapping, sizeof (NXParsedKeyMapping) );
550	parsedMapping->maxMod = -1;
551	parsedMapping->numDefs = -1;
552	parsedMapping->numSeqs = -1;
553
554		if (!map || !mappingLen)
555			return false;
556
557	nmd.endPtr = map + mappingLen;
558	nmd.bp = map;
559	nmd.shorts = 1;		// First value, the size, is always a short
560
561	/* Start filling it in with the new data */
562	parsedMapping->mapping = (unsigned char *)map;
563	parsedMapping->mappingLen = mappingLen;
564	parsedMapping->shorts = nmd.shorts = NextNum(&nmd);
565
566	/* Walk through the modifier definitions */
567	numMods = NextNum(&nmd);
568	for(i=0; i<numMods; i++)
569	{
570		/* Get bit number */
571		if ((j = NextNum(&nmd)) >= NX_NUMMODIFIERS)
572		return false;
573
574		/* Check maxMod */
575		if (j > parsedMapping->maxMod)
576		parsedMapping->maxMod = j;
577
578		/* record position of this def */
579		parsedMapping->modDefs[j] = (unsigned char *)nmd.bp;
580
581		/* Loop through each key assigned to this bit */
582		for(k=0,n = NextNum(&nmd);k<n;k++)
583		{
584		/* Check that key code is valid */
585		if ((l = NextNum(&nmd)) >= NX_NUMKEYCODES)
586			return false;
587		/* Make sure the key's not already assigned */
588		if (parsedMapping->keyBits[l] & NX_MODMASK)
589			return false;
590		/* Set bit for modifier and which one */
591
592		//The "if" here is to patch the keymapping file.  That file has nothing
593		// for num lock, so no change is required here for num lock.
594		// Also, laptop Macs have num lock handled by Buttons driver
595		if ((j != NX_MODIFIERKEY_ALPHALOCK) || (_delegate->doesKeyLock(NX_KEYTYPE_CAPS_LOCK)) )
596		{
597			parsedMapping->keyBits[l] |=NX_MODMASK | (j & NX_WHICHMODMASK);
598		}
599
600		}
601	}
602
603	//This is here because keymapping file has an entry for caps lock, but in
604	//	order to trigger special code (line 646-), the entry needs to be zero
605	if (!_delegate->doesKeyLock(NX_KEYTYPE_CAPS_LOCK))
606		parsedMapping->modDefs[NX_MODIFIERKEY_ALPHALOCK] = 0;
607
608	//This section is here to force keymapping to include the PowerBook's secondary
609	// fn key as a new modifier key.  This code can be removed once the keymapping
610	// file has the fn key (ADB=0x3f) in the modifiers section.
611	// NX_MODIFIERKEY_SECONDARYFN = 8 in ev_keymap.h
612	if (_delegate->interfaceID() == NX_EVS_DEVICE_INTERFACE_ADB)
613	{
614		parsedMapping->keyBits[0x3f] |=NX_MODMASK | (NX_MODIFIERKEY_SECONDARYFN & NX_WHICHMODMASK);
615	}
616
617	/* Walk through each key definition */
618	parsedMapping->numDefs = NextNum(&nmd);
619	n = parsedMapping->numDefs;
620	for( i=0; i < NX_NUMKEYCODES; i++)
621	{
622		if (i < n)
623		{
624		parsedMapping->keyDefs[i] = (unsigned char *)nmd.bp;
625		if ((keyMask = NextNum(&nmd)) != (nmd.shorts ? 0xFFFF: 0x00FF))
626		{
627			/* Set char gen bit for this guy: not a no-op */
628			parsedMapping->keyBits[i] |= NX_CHARGENMASK;
629			/* Check key defs to find max sequence number */
630			for(j=0, k=1; j<=parsedMapping->maxMod; j++, keyMask>>=1)
631			{
632				if (keyMask & 0x01)
633				k*= 2;
634			}
635			for(j=0; j<k; j++)
636			{
637			m = NextNum(&nmd);
638			l = NextNum(&nmd);
639			if (m == (unsigned)(nmd.shorts ? 0xFFFF: 0x00FF))
640				if (((int)l) > maxSeqNum)
641				maxSeqNum = l;	/* Update expected # of seqs */
642			}
643		}
644		else /* unused code within active range */
645			parsedMapping->keyDefs[i] = NULL;
646		}
647		else /* Unused code past active range */
648		{
649		parsedMapping->keyDefs[i] = NULL;
650		}
651	}
652	/* Walk through sequence defs */
653	parsedMapping->numSeqs = NextNum(&nmd);
654		/* If the map calls more sequences than are declared, bail out */
655	if (parsedMapping->numSeqs <= maxSeqNum)
656		return false;
657
658    if (parsedMapping->numSeqs > NX_NUMSEQUENCES)
659        return false;
660
661	/* Walk past all sequences */
662	for(i = 0; i < parsedMapping->numSeqs; i++)
663	{
664		parsedMapping->seqDefs[i] = (unsigned char *)nmd.bp;
665		/* Walk thru entries in a seq. */
666		for(j=0, l=NextNum(&nmd); j<l; j++)
667		{
668		NextNum(&nmd);
669		NextNum(&nmd);
670		}
671	}
672	/* Install Special device keys.	 These override default values. */
673	numMods = NextNum(&nmd);	/* Zero on old style keymaps */
674	parsedMapping->numSpecialKeys = numMods;
675	if ( numMods > NX_NUMSPECIALKEYS )
676		return false;
677	if ( numMods )
678	{
679		for ( i = 0; i < NX_NUMSPECIALKEYS; ++i )
680		parsedMapping->specialKeys[i] = NX_NOSPECIALKEY;
681
682			//This "if" will cover both ADB and USB keyboards.	This code does not
683			//	have to be here if the keymaps include these two entries.  Keyboard
684		//	drivers already have these entries, but keymapping file does not
685		if (_delegate->interfaceID() == NX_EVS_DEVICE_INTERFACE_ADB)
686		{
687		//ADB capslock:
688			parsedMapping->specialKeys[NX_KEYTYPE_CAPS_LOCK] = 0x39;
689
690		//ADB numlock for external keyboards, not PowerBook keyboards:
691			parsedMapping->specialKeys[NX_KEYTYPE_NUM_LOCK] = 0x47;
692
693		//HELP key needs to be visible
694		parsedMapping->keyDefs[0x72] = parsedMapping->keyDefs[0x47];
695		}
696
697		//Keymapping file can override caps and num lock above now:
698		for ( i = 0; i < numMods; ++i )
699		{
700		j = NextNum(&nmd);	/* Which modifier key? */
701		l = NextNum(&nmd);	/* Scancode for modifier key */
702		if ( j >= NX_NUMSPECIALKEYS )
703			return false;
704		parsedMapping->specialKeys[j] = l;
705		}
706	}
707	else  /* No special keys defs implies an old style keymap */
708	{
709		return false;	/* Old style keymaps are guaranteed to do */
710				/* the wrong thing on ADB keyboards */
711	}
712
713	/* Install bits for Special device keys */
714	for(i=0; i<NX_NUM_SCANNED_SPECIALKEYS; i++)
715	{
716		if ( parsedMapping->specialKeys[i] != NX_NOSPECIALKEY )
717		{
718			if (parsedMapping->specialKeys[i] < NX_NUMKEYCODES)
719				parsedMapping->keyBits[parsedMapping->specialKeys[i]] |= (NX_CHARGENMASK | NX_SPECIALKEYMASK);
720		}
721	}
722
723	//caps lock keys should not generate characters.
724	if (_delegate->doesKeyLock(NX_KEYTYPE_CAPS_LOCK))
725	{
726		if (parsedMapping->specialKeys[NX_KEYTYPE_CAPS_LOCK] < NX_NUMKEYCODES)
727			parsedMapping->keyBits[ parsedMapping->specialKeys[NX_KEYTYPE_CAPS_LOCK] ] &= ~NX_CHARGENMASK;
728	}
729
730	//Find scan code corresponding to PowerBook fn key (0x3f in ADB)
731	//	 and then make sure it does not generate a character
732	bp = _parsedMapping.modDefs[NX_MODIFIERKEY_SECONDARYFN];  //7th array entry
733	if (bp)
734	{
735			bp++;  //now points to actual ADB scan code
736			parsedMapping->keyBits[ *bp ] &= ~NX_CHARGENMASK;
737	}
738
739    if (parsedMapping->specialKeys[NX_MODIFIERKEY_ALPHALOCK_STATELESS] == NX_NOSPECIALKEY) {
740        // check value of keyDefs
741        unsigned char key = NX_NUMKEYCODES - 1;
742        parsedMapping->specialKeys[NX_MODIFIERKEY_ALPHALOCK_STATELESS] = key;
743        parsedMapping->modDefs[NX_MODIFIERKEY_ALPHALOCK_STATELESS] = 0;
744        parsedMapping->keyBits[key] = NX_MODIFIERKEY_ALPHALOCK_STATELESS | NX_MODMASK;
745    }
746    else {
747        //IOLog("Stateless alpha lock defined in mapping as %02x\n", parsedMapping->specialKeys[NX_MODIFIERKEY_ALPHALOCK_STATELESS]);
748    }
749
750	return true;
751}
752
753
754//Retrieve a key from mapping above.  Useful for IOHIKeyboard
755UInt8 IOHIKeyboardMapper::getParsedSpecialKey(UInt8 logical)
756{
757	UInt8	retval;
758
759	if ( logical < NX_NUMSPECIALKEYS)
760	retval = _parsedMapping.specialKeys[logical];
761	else
762	retval = 0xff;	//careful, 0 is mapped already
763	return retval;
764}
765
766
767static inline int NEXTNUM(unsigned char ** mapping, short shorts)
768{
769	int returnValue;
770
771	if (shorts)
772	{
773		returnValue = OSSwapBigToHostInt16(*((unsigned short *)*mapping));
774		*mapping += sizeof(unsigned short);
775	}
776	else
777	{
778		returnValue = **((unsigned char	 **)mapping);
779		*mapping += sizeof(unsigned char);
780	}
781
782	return returnValue;
783}
784
785bool IOHIKeyboardMapper::modifierSwapFilterKey(UInt8 * key)
786{
787	unsigned char	thisBits = _parsedMapping.keyBits[*key];
788	SInt16			modBit = (thisBits & NX_WHICHMODMASK);
789	SInt16			swapBit;
790	unsigned char	*map;
791
792	if (!(thisBits & NX_MODMASK))
793	{
794		if (*key == getParsedSpecialKey(NX_KEYTYPE_CAPS_LOCK)) {
795			modBit = NX_MODIFIERKEY_ALPHALOCK;
796		}
797		else {
798			return false;
799		}
800	}
801
802	if (modBit > NX_MODIFIERKEY_LAST_KEY) {
803		return false;
804    }
805
806	swapBit = _modifierSwap_Modifiers[modBit];
807
808	if (swapBit == modBit)
809	{
810		// RY: Handle situation where modifiers were mapped to CapsLock on
811		// physically locking caps keyboards.  In this case, we want to restore
812		// the NX_MODIFIERKEY_ALPHALOCK modDef and remove the char generation.
813		// This will deactivate the AlphaLock toggle behavior.
814		if (_delegate->doesKeyLock(NX_KEYTYPE_CAPS_LOCK) && (swapBit == NX_MODIFIERKEY_ALPHALOCK))
815		{
816			if (_parsedMapping.specialKeys[NX_KEYTYPE_CAPS_LOCK] < NX_NUMKEYCODES)
817				_parsedMapping.keyBits[ _parsedMapping.specialKeys[NX_KEYTYPE_CAPS_LOCK] ] &= ~NX_CHARGENMASK;
818			_parsedMapping.modDefs[NX_MODIFIERKEY_ALPHALOCK] = _cachedAlphaLockModDefs;
819			_specialKeyModifierFlags &= ~NX_ALPHASHIFTMASK;
820		}
821		return false;
822	}
823	else if (swapBit == -1)
824	{
825		return true;
826	}
827
828	// RY: Handle situation where modifiers are being mapped to CapsLock on
829	// physically locking caps keyboards.  In this case, we want to remove
830	// the NX_MODIFIERKEY_ALPHALOCK modDef and generate a char.	 This will
831	// activate the AlphaLock toggle behavior.
832	if (_delegate->doesKeyLock(NX_KEYTYPE_CAPS_LOCK) && (swapBit == NX_MODIFIERKEY_ALPHALOCK))
833	{
834		if (_parsedMapping.specialKeys[NX_KEYTYPE_CAPS_LOCK] < NX_NUMKEYCODES)
835			_parsedMapping.keyBits[ _parsedMapping.specialKeys[NX_KEYTYPE_CAPS_LOCK] ] |= NX_CHARGENMASK;
836		_parsedMapping.modDefs[NX_MODIFIERKEY_ALPHALOCK] = 0;
837	}
838
839	if (((map = _parsedMapping.modDefs[swapBit]) != 0 ) && ( NEXTNUM(&map, _parsedMapping.shorts) )) {
840		*key = NEXTNUM(&map, _parsedMapping.shorts);
841    }
842	else if (swapBit == NX_MODIFIERKEY_ALPHALOCK) {
843		*key = getParsedSpecialKey(NX_KEYTYPE_CAPS_LOCK);
844    }
845    else if (swapBit == NX_MODIFIERKEY_ALPHALOCK_STATELESS) {
846		*key = getParsedSpecialKey(NX_MODIFIERKEY_ALPHALOCK_STATELESS);
847    }
848
849	return false;
850}
851
852//
853// Look up in the keymapping each key associated with the modifier bit.
854// Look in the device state to see if that key is down.
855// Return 1 if a key for modifier 'bit' is down.  Return 0 if none is down
856//
857static inline int IsModifierDown(NXParsedKeyMapping *parsedMapping,
858				 kbdBitVector keyBits,
859				 int bit )
860{
861	int i, n;
862	unsigned char *mapping;
863	unsigned key;
864	short shorts = parsedMapping->shorts;
865
866	if ( (mapping = parsedMapping->modDefs[bit]) != 0 ) {
867	for(i=0, n=NEXTNUM(&mapping, shorts); i<n; i++)
868	{
869		key = NEXTNUM(&mapping, shorts);
870		if ( EVK_IS_KEYDOWN(key, keyBits) )
871		return 1;
872	}
873	}
874	return 0;
875}
876
877void IOHIKeyboardMapper::calcModBit(int bit, kbdBitVector keyBits)
878{
879		int			otherHandBit	= 0;
880		int			deviceBitMask	= 0;
881	int		systemBitMask	= 0;
882	unsigned	myFlags		= 0;
883
884		systemBitMask = 1<<(bit+16);
885		deviceBitMask = DeviceModifierMasks[bit];
886
887		if ((bit >= NX_MODIFIERKEY_RSHIFT) && (bit <= NX_MODIFIERKEY_RCOMMAND))
888		{
889			otherHandBit = bit - 8;
890			systemBitMask = 1<<(otherHandBit+16);
891		}
892		else if ((bit >= NX_MODIFIERKEY_SHIFT) && (bit <= NX_MODIFIERKEY_COMMAND))
893		{
894			otherHandBit = bit + 8;
895		}
896
897		/* Initially clear bit, as if key-up */
898		myFlags = _delegate->deviceFlags() & (~systemBitMask);
899		myFlags &= ~deviceBitMask;
900
901		/* Set bit if any associated keys are down */
902		if ( IsModifierDown( &_parsedMapping, keyBits, bit ))
903		{
904				myFlags |= (systemBitMask | deviceBitMask);
905		}
906		else if (deviceBitMask &&
907				IsModifierDown( &_parsedMapping, keyBits, otherHandBit ))
908		{
909				myFlags |= (systemBitMask);
910		}
911
912		myFlags |= _specialKeyModifierFlags;
913
914	if ( bit == NX_MODIFIERKEY_ALPHALOCK ) {/* Caps Lock key */
915		_delegate->setAlphaLock((myFlags & NX_ALPHASHIFTMASK) ? true : false);
916    }
917	else if ( bit == NX_MODIFIERKEY_NUMLOCK ) {/* Num Lock key */
918			_delegate->setNumLock((myFlags & NX_NUMERICPADMASK) ? true : false);
919	}
920
921	_delegate->setDeviceFlags(myFlags);
922
923}
924
925
926//
927// Perform flag state update and generate flags changed events for this key.
928//
929void IOHIKeyboardMapper::doModCalc(int key, kbdBitVector keyBits)
930{
931	int thisBits;
932	thisBits = _parsedMapping.keyBits[key];
933	if (thisBits & NX_MODMASK)
934	{
935	calcModBit((thisBits & NX_WHICHMODMASK), keyBits);
936	/* The driver generates flags-changed events only when there is
937	   no key-down or key-up event generated */
938	if (!(thisBits & NX_CHARGENMASK))
939	{
940		/* Post the flags-changed event */
941		_delegate->keyboardEvent(NX_FLAGSCHANGED,
942		 /* flags */			_delegate->eventFlags(),
943		 /* keyCode */			key,
944		 /* charCode */			0,
945		 /* charSet */			0,
946		 /* originalCharCode */ 0,
947		 /* originalCharSet */	0);
948#ifdef NEW_HID
949		_delegate->keyboardEvent(EVK_IS_KEYDOWN(key, keyBits) ? NX_KEYDOWN : NX_KEYUP,
950		 /* flags */			_delegate->eventFlags(),
951		 /* keyCode */			key,
952		 /* charCode */			0,
953		 /* charSet */			0,
954		 /* originalCharCode */ 0,
955		 /* originalCharSet */	0);
956#endif
957	}
958	else	/* Update, but don't generate an event */
959		_delegate->updateEventFlags(_delegate->eventFlags());
960	}
961}
962
963//
964// Perform character event generation for this key
965//
966void IOHIKeyboardMapper::doCharGen(int keyCode, bool down)
967{
968	int i, n, eventType, adjust, thisMask, modifiers, saveModifiers;
969	short shorts;
970	unsigned charSet, origCharSet;
971	unsigned charCode, origCharCode;
972    unsigned char *map;
973	unsigned eventFlags, origflags;
974
975	_delegate->setCharKeyActive(true);	// a character generating key is active
976
977	eventType = (down == true) ? NX_KEYDOWN : NX_KEYUP;
978	eventFlags = _delegate->eventFlags();
979	saveModifiers = eventFlags >> 16;	// machine independent mod bits
980	/* Set NX_ALPHASHIFTMASK based on alphaLock OR shift active */
981	if( saveModifiers & (NX_SHIFTMASK >> 16))
982	saveModifiers |= (NX_ALPHASHIFTMASK >> 16);
983
984
985	/* Get this key's key mapping */
986	shorts = _parsedMapping.shorts;
987    map = _parsedMapping.keyDefs[keyCode];
988	modifiers = saveModifiers;
989    if ( map ) {
990
991
992	/* Build offset for this key */
993        thisMask = NEXTNUM(&map, shorts);
994        if (thisMask && modifiers) {
995		adjust = (shorts ? sizeof(short) : sizeof(char))*2;
996            for ( i = 0; i <= _parsedMapping.maxMod; ++i) {
997                if (thisMask & 0x01) {
998			if (modifiers & 0x01)
999                        map += adjust;
1000			adjust *= 2;
1001		}
1002		thisMask >>= 1;
1003		modifiers >>= 1;
1004		}
1005	}
1006        charSet = NEXTNUM(&map, shorts);
1007        charCode = NEXTNUM(&map, shorts);
1008
1009	/* construct "unmodified" character */
1010        map = _parsedMapping.keyDefs[keyCode];
1011		modifiers = saveModifiers & ((NX_ALPHASHIFTMASK | NX_SHIFTMASK) >> 16);
1012
1013        thisMask = NEXTNUM(&map, shorts);
1014        if (thisMask && modifiers) {
1015		adjust = (shorts ? sizeof(short) : sizeof(char)) * 2;
1016            for ( i = 0; i <= _parsedMapping.maxMod; ++i) {
1017                if (thisMask & 0x01) {
1018			if (modifiers & 0x01)
1019                        map += adjust;
1020			adjust *= 2;
1021		}
1022		thisMask >>= 1;
1023		modifiers >>= 1;
1024		}
1025	}
1026        origCharSet = NEXTNUM(&map, shorts);
1027        origCharCode = NEXTNUM(&map, shorts);
1028
1029        if (charSet == (unsigned)(shorts ? 0xFFFF : 0x00FF)) {
1030		// Process as a character sequence
1031		// charCode holds the sequence number
1032            map = _parsedMapping.seqDefs[charCode];
1033
1034		origflags = eventFlags;
1035            for (i=0,n=NEXTNUM(&map, shorts);i<n;i++) {
1036                if ( (charSet = NEXTNUM(&map, shorts)) == 0xFF ) { /* metakey */
1037                    if ( down == true ) { /* down or repeat */
1038                        eventFlags |= (1 << (NEXTNUM(&map, shorts) + 16));
1039			_delegate->keyboardEvent(NX_FLAGSCHANGED,
1040			 /* flags */			_delegate->deviceFlags(),
1041			 /* keyCode */			keyCode,
1042			 /* charCode */			0,
1043			 /* charSet */			0,
1044			 /* originalCharCode */ 0,
1045			 /* originalCharSet */	0);
1046			}
1047			else
1048                        NEXTNUM(&map, shorts); /* Skip over value */
1049		}
1050                else {
1051                    charCode = NEXTNUM(&map, shorts);
1052			_delegate->keyboardEvent(eventType,
1053			 /* flags */			eventFlags,
1054			 /* keyCode */			keyCode,
1055			 /* charCode */			charCode,
1056			 /* charSet */			charSet,
1057			 /* originalCharCode */ charCode,
1058			 /* originalCharSet */	charSet);
1059		}
1060		}
1061		/* Done with macro.	 Restore the flags if needed. */
1062            if ( eventFlags != origflags ) {
1063		_delegate->keyboardEvent(NX_FLAGSCHANGED,
1064		 /* flags */			_delegate->deviceFlags(),
1065		 /* keyCode */			keyCode,
1066		 /* charCode */			0,
1067		 /* charSet */			0,
1068		 /* originalCharCode */ 0,
1069		 /* originalCharSet */	0);
1070		eventFlags = origflags;
1071		}
1072	}
1073        else { /* A simple character generating key */
1074		_delegate->keyboardEvent(eventType,
1075		 /* flags */			eventFlags,
1076		 /* keyCode */			keyCode,
1077		 /* charCode */			charCode,
1078		 /* charSet */			charSet,
1079		 /* originalCharCode */ origCharCode,
1080		 /* originalCharSet */	origCharSet);
1081	}
1082    } /* if (map) */
1083
1084	/*
1085	 * Check for a device control key: note that they always have CHARGEN
1086	 * bit set
1087	 */
1088    if (_parsedMapping.keyBits[keyCode] & NX_SPECIALKEYMASK) {
1089        for (i=0; i<NX_NUM_SCANNED_SPECIALKEYS; i++) {
1090            if ( keyCode == _parsedMapping.specialKeys[i] ) {
1091		_delegate->keyboardSpecialEvent(eventType,
1092					/* flags */		eventFlags,
1093					/* keyCode */	keyCode,
1094					/* specialty */ i);
1095		/*
1096		 * Special keys hack for letting an arbitrary (non-locking)
1097		 * key act as a CAPS-LOCK key.	If a special CAPS LOCK key
1098		 * is designated, and there is no key designated for the
1099		 * AlphaLock function, then we'll let the special key toggle
1100		 * the AlphaLock state.
1101		 */
1102		if (i == NX_KEYTYPE_CAPS_LOCK
1103			&& down == true
1104                        && !_parsedMapping.modDefs[NX_MODIFIERKEY_ALPHALOCK] ) {
1105			unsigned myFlags = _delegate->deviceFlags();
1106			bool alphaLock = (_delegate->alphaLock() == false);
1107
1108			// Set delegate's alphaLock state
1109			_delegate->setAlphaLock(alphaLock);
1110			// Update the delegate's flags
1111                    if ( alphaLock ) {
1112				myFlags |= NX_ALPHASHIFTMASK;
1113						_specialKeyModifierFlags |= NX_ALPHASHIFTMASK;
1114					}
1115                    else {
1116				myFlags &= ~NX_ALPHASHIFTMASK;
1117						_specialKeyModifierFlags &= ~NX_ALPHASHIFTMASK;
1118					}
1119
1120			_delegate->setDeviceFlags(myFlags);
1121
1122			_delegate->keyboardEvent(NX_FLAGSCHANGED,
1123			 /* flags */			myFlags,
1124			 /* keyCode */			keyCode,
1125			 /* charCode */			0,
1126			 /* charSet */			0,
1127			 /* originalCharCode */ 0,
1128			 /* originalCharSet */	0);
1129
1130#ifdef NEW_HID
1131			_delegate->keyboardEvent(alphaLock ? NX_KEYDOWN : NX_KEYUP,
1132			 /* flags */			myFlags,
1133			 /* keyCode */			keyCode,
1134			 /* charCode */			0,
1135			 /* charSet */			0,
1136			 /* originalCharCode */ 0,
1137			 /* originalCharSet */	0);
1138#endif
1139		}
1140		else	if (i == NX_KEYTYPE_NUM_LOCK
1141			&& down == true
1142					&& (_delegate->doesKeyLock(NX_KEYTYPE_NUM_LOCK) || _delegate->metaCast("AppleADBButtons"))
1143                         && !_parsedMapping.modDefs[NX_MODIFIERKEY_NUMLOCK] ) {
1144			unsigned myFlags = _delegate->deviceFlags();
1145			bool numLock = (_delegate->numLock() == false);
1146
1147			// Set delegate's numLock state
1148					_delegate->setNumLock(numLock);
1149                    if ( numLock ) {
1150				myFlags |= NX_NUMERICPADMASK;
1151						_specialKeyModifierFlags |= NX_NUMERICPADMASK;
1152					}
1153                    else {
1154				myFlags &= ~NX_NUMERICPADMASK;
1155						_specialKeyModifierFlags &= ~NX_NUMERICPADMASK;
1156					}
1157
1158			_delegate->setDeviceFlags(myFlags);
1159			_delegate->keyboardEvent(NX_FLAGSCHANGED,
1160			 /* flags */			myFlags,
1161			 /* keyCode */			keyCode,
1162			 /* charCode */			0,
1163			 /* charSet */			0,
1164			 /* originalCharCode */ 0,
1165			 /* originalCharSet */	0);
1166		}
1167
1168		break;
1169		}
1170	}
1171	}
1172}
1173
1174
1175void IOHIKeyboardMapper::setKeyboardTarget (IOService * keyboardTarget)
1176{
1177	_hidSystem = OSDynamicCast( IOHIDSystem, keyboardTarget );
1178}
1179
1180void IOHIKeyboardMapper::makeNumberParamProperty( OSDictionary * dict,
1181							const char * key,
1182							unsigned long long number, unsigned int bits )
1183{
1184	OSNumber *	numberRef;
1185	numberRef = OSNumber::withNumber(number, bits);
1186
1187	if( numberRef) {
1188		dict->setObject( key, numberRef);
1189		numberRef->release();
1190	}
1191}
1192
1193bool IOHIKeyboardMapper::updateProperties( void )
1194{
1195	bool	ok = true;
1196
1197	return( ok );
1198}
1199
1200IOReturn IOHIKeyboardMapper::setParamProperties( OSDictionary * dict )
1201{
1202	OSNumber *		number					= 0;
1203	OSData *		data					= 0;
1204	OSArray *		array					= 0;
1205	IOReturn		err						= kIOReturnSuccess;
1206	bool			updated					= false;
1207	UInt32			value					= 0;
1208	bool			issueFlagsChangedEvent	= false;
1209	bool			alphaState				= false;
1210	UInt32			myFlags					= _delegate->deviceFlags();
1211	UInt32			ledStatus				= 0;
1212
1213	// Check for eject delay property
1214	if ((number = OSDynamicCast(OSNumber,
1215							  dict->getObject(kIOHIDF12EjectDelayKey))) ||
1216		(data = OSDynamicCast(OSData,
1217							  dict->getObject(kIOHIDF12EjectDelayKey))))
1218	{
1219		value = (number) ? number->unsigned32BitValue() : *((UInt32 *) (data->getBytesNoCopy()));
1220
1221		// we know we set this as a 32 bit number
1222		_eject_Delay_MS = value;
1223
1224		// we changed something
1225		updated = true;
1226	}
1227
1228	// Check for fkey mode property
1229	if ((number = OSDynamicCast(OSNumber,
1230							  dict->getObject(kIOHIDMouseKeysOnKey))) ||
1231		(data = OSDynamicCast(OSData,
1232							  dict->getObject(kIOHIDMouseKeysOnKey))))
1233	{
1234		value = (number) ? number->unsigned32BitValue() : *((UInt32 *) (data->getBytesNoCopy()));
1235
1236		// if set, then set the bit in our state
1237		if (value)
1238				_stickyKeys_State |= kState_MouseKeyStateOn;
1239		// otherwise clear the bit in our state
1240		else
1241				_stickyKeys_State &= ~kState_MouseKeyStateOn;
1242
1243		// we changed something
1244		updated = true;
1245	}
1246
1247	// Check for slowKeys delay property
1248	if ((number = OSDynamicCast(OSNumber,
1249							  dict->getObject(kIOHIDSlowKeysDelayKey))) ||
1250		(data = OSDynamicCast(OSData,
1251							  dict->getObject(kIOHIDSlowKeysDelayKey))))
1252	{
1253		value = (number) ? number->unsigned32BitValue() : *((UInt32 *) (data->getBytesNoCopy()));
1254		// If we are in progess and we are turned off
1255		// cancel the timeout
1256		if ((_slowKeys_Delay_MS > 0) && !value &&
1257			((_slowKeys_State & kState_In_Progess_Flag) != 0))
1258			_slowKeysTimerEventSource->cancelTimeout();
1259
1260
1261		_slowKeys_Delay_MS = value;
1262
1263		// we changed something
1264		updated = true;
1265	}
1266
1267	// check for disabled property in the dictionary
1268	if ((number = OSDynamicCast(OSNumber,
1269							  dict->getObject(kIOHIDStickyKeysDisabledKey))) ||
1270		(data = OSDynamicCast(OSData,
1271							  dict->getObject(kIOHIDStickyKeysDisabledKey))))
1272	{
1273		value = (number) ? number->unsigned32BitValue() : *((UInt32 *) (data->getBytesNoCopy()));
1274
1275		// if set, then set the bit in our state
1276		if (value)
1277		{
1278				_stickyKeys_State |= kState_Disabled_Flag;
1279				stickyKeysCleanup();
1280		}
1281		// otherwise clear the bit in our state
1282		else
1283				_stickyKeys_State &= ~kState_Disabled_Flag;
1284
1285		// we changed something
1286		updated = true;
1287	}
1288
1289	// check for on/off property in the dictionary
1290	if ((number = OSDynamicCast(OSNumber,
1291							  dict->getObject(kIOHIDStickyKeysOnKey))) ||
1292		(data = OSDynamicCast(OSData,
1293							  dict->getObject(kIOHIDStickyKeysOnKey))))
1294	{
1295		value = (number) ? number->unsigned32BitValue() : *((UInt32 *) (data->getBytesNoCopy()));
1296
1297		// if set, then set the bit in our state
1298		if (value) {
1299				_stickyKeys_State |= kState_On;
1300		}
1301		// otherwise clear the bit in our state
1302		else {
1303		stickyKeysCleanup();
1304		}
1305
1306		// we changed something
1307		updated = true;
1308	}
1309
1310	// Check for fkey mode property
1311	if ((dict->getObject(kIOHIDTemporaryParametersKey) == NULL) &&
1312		((NULL != (number = OSDynamicCast(OSNumber, dict->getObject(kIOHIDFKeyModeKey)))) ||
1313		 (NULL != (data = OSDynamicCast(OSData, dict->getObject(kIOHIDFKeyModeKey))))))
1314	{
1315		value = (number) ? number->unsigned32BitValue() : *((UInt32 *) (data->getBytesNoCopy()));
1316
1317		// if set, then set the bit in our state
1318		if (value)
1319				_stickyKeys_State |= kState_PrefFnKeyStateOn;
1320		// otherwise clear the bit in our state
1321		else
1322				_stickyKeys_State &= ~kState_PrefFnKeyStateOn;
1323
1324		// we changed something
1325		updated = true;
1326	}
1327
1328	// check for shift toggles property in the dictionary
1329	if ((number = OSDynamicCast(OSNumber,
1330							  dict->getObject(kIOHIDStickyKeysShiftTogglesKey))) ||
1331		(data = OSDynamicCast(OSData,
1332							  dict->getObject(kIOHIDStickyKeysShiftTogglesKey))))
1333	{
1334		value = (number) ? number->unsigned32BitValue() : *((UInt32 *) (data->getBytesNoCopy()));
1335
1336		// if set, then set the bit in our state
1337		if (value)
1338				_stickyKeys_State |= kState_ShiftActivates_Flag;
1339		// otherwise clear the bit in our state
1340		else
1341				_stickyKeys_State &= ~kState_ShiftActivates_Flag;
1342
1343		// we changed something
1344		updated = true;
1345	}
1346
1347	// check for shift toggles property in the dictionary
1348	if ((number = OSDynamicCast(OSNumber,
1349							  dict->getObject(kIOHIDMouseKeysOptionTogglesKey))) ||
1350		(data = OSDynamicCast(OSData,
1351							  dict->getObject(kIOHIDMouseKeysOptionTogglesKey))))
1352	{
1353		value = (number) ? number->unsigned32BitValue() : *((UInt32 *) (data->getBytesNoCopy()));
1354
1355		// if set, then set the bit in our state
1356		if (value)
1357				_stickyKeys_State |= kState_OptionActivates_Flag;
1358		// otherwise clear the bit in our state
1359		else
1360				_stickyKeys_State &= ~kState_OptionActivates_Flag;
1361
1362		// we changed something
1363		updated = true;
1364	}
1365
1366	if ((array = OSDynamicCast(OSArray, dict->getObject(kIOHIDKeyboardModifierMappingPairsKey))) && (_parsedMapping.maxMod != -1))
1367	{
1368		UInt32 count = array->getCount();
1369
1370		if ( count )
1371		{
1372			for ( unsigned i=0; i<count; i++)
1373			{
1374				OSDictionary *	pair			= OSDynamicCast(OSDictionary, array->getObject(i));
1375				UInt32			src				= 0;
1376				UInt32			dst				= 0;
1377
1378				if ( !pair ) continue;
1379
1380				number = OSDynamicCast(OSNumber, pair->getObject(kIOHIDKeyboardModifierMappingSrcKey));
1381
1382				if ( !number ) continue;
1383
1384				src = number->unsigned32BitValue();
1385
1386				number = OSDynamicCast(OSNumber, pair->getObject(kIOHIDKeyboardModifierMappingDstKey));
1387
1388				if ( !number ) continue;
1389
1390				dst = number->unsigned32BitValue();
1391
1392				if ( src == NX_MODIFIERKEY_ALPHALOCK )
1393				{
1394					ledStatus = _delegate->getLEDStatus();
1395
1396					if (dst == NX_MODIFIERKEY_ALPHALOCK)
1397					{
1398						if ((ledStatus & 0x2) && !(myFlags & NX_ALPHASHIFTMASK))
1399						{
1400							issueFlagsChangedEvent	= true;
1401							alphaState				= true;
1402						}
1403						else if (!(ledStatus & 0x2) && (myFlags & NX_ALPHASHIFTMASK))
1404						{
1405							issueFlagsChangedEvent	= true;
1406							alphaState				= false;
1407						}
1408					}
1409					else if (_delegate->doesKeyLock(NX_KEYTYPE_CAPS_LOCK) && (dst != -1))
1410					{
1411						continue;
1412					}
1413					else
1414					{
1415						issueFlagsChangedEvent	= true;
1416						alphaState				= false;
1417					}
1418				}
1419
1420				if ((src >= NX_MODIFIERKEY_ALPHALOCK) &&
1421					(src <= NX_MODIFIERKEY_LAST_KEY) &&
1422					((dst < NX_NUMMODIFIERS) || (dst == (UInt32) -1)) )
1423						_modifierSwap_Modifiers[src] = dst;
1424			}
1425		}
1426		else
1427		{
1428			for (unsigned i=0; i<NX_NUMMODIFIERS; i++)
1429			{
1430				if (((i == NX_MODIFIERKEY_ALPHALOCK) && (_modifierSwap_Modifiers[i] != NX_MODIFIERKEY_ALPHALOCK)) ||
1431					((i != NX_MODIFIERKEY_ALPHALOCK) && (_modifierSwap_Modifiers[i] == NX_MODIFIERKEY_ALPHALOCK)))
1432				{
1433					ledStatus = _delegate->getLEDStatus();
1434
1435					if ((ledStatus & 0x2) && !(myFlags & NX_ALPHASHIFTMASK))
1436					{
1437						issueFlagsChangedEvent	= true;
1438						alphaState				= true;
1439					}
1440					else if (!(ledStatus & 0x2) && (myFlags & NX_ALPHASHIFTMASK))
1441					{
1442						issueFlagsChangedEvent	= true;
1443						alphaState				= false;
1444					}
1445				}
1446
1447				_modifierSwap_Modifiers[i] = i;
1448			}
1449
1450		}
1451
1452	}
1453
1454	if ( issueFlagsChangedEvent )
1455	{
1456		if ( alphaState )
1457		{
1458			if ( !_delegate->doesKeyLock(NX_KEYTYPE_CAPS_LOCK) )
1459			{
1460				_specialKeyModifierFlags |= NX_ALPHASHIFTMASK;
1461			}
1462
1463			myFlags |= NX_ALPHASHIFTMASK;
1464
1465			_delegate->setDeviceFlags(myFlags);
1466			_delegate->setAlphaLock(true);
1467		}
1468		else
1469		{
1470			_specialKeyModifierFlags	&= ~NX_ALPHASHIFTMASK;
1471			myFlags						&= ~NX_ALPHASHIFTMASK;
1472
1473			_delegate->setDeviceFlags(myFlags);
1474			_delegate->setAlphaLock(false);
1475		}
1476
1477		UInt8			keyCode;
1478		unsigned char	*map;
1479
1480		if (((map = _parsedMapping.modDefs[NX_MODIFIERKEY_ALPHALOCK]) != 0 ) &&
1481			( NEXTNUM(&map, _parsedMapping.shorts) ))
1482			keyCode = NEXTNUM(&map, _parsedMapping.shorts);
1483		else
1484			keyCode = getParsedSpecialKey(NX_KEYTYPE_CAPS_LOCK);
1485
1486		_delegate->keyboardEvent(NX_FLAGSCHANGED,
1487		 /* flags */			myFlags,
1488		 /* keyCode */			keyCode,
1489		 /* charCode */			0,
1490		 /* charSet */			0,
1491		 /* originalCharCode */ 0,
1492		 /* originalCharSet */	0);
1493
1494
1495#ifdef NEW_HID
1496		_delegate->keyboardEvent(alphaState ? NX_KEYDOWN : NX_KEYUP,
1497		 /* flags */			myFlags,
1498		 /* keyCode */			keyCode,
1499		 /* charCode */			0,
1500		 /* charSet */			0,
1501		 /* originalCharCode */ 0,
1502		 /* originalCharSet */	0);
1503#endif
1504	}
1505
1506	// right now updateProperties does nothing interesting
1507	if (updated)
1508		updateProperties();
1509
1510	return( err );
1511}
1512
1513// ************* Sticky Keys Functionality ****************
1514
1515// stickyKeysinit
1516// initialize sticky keys variables
1517bool IOHIKeyboardMapper::stickyKeysinit( void )
1518{
1519	// default state to off, unless the UI part is installed and turns us on.
1520	// instead of setting shifttoggles and disabled, which would be the other way to do it
1521	// we will just keep all flags clear, making us off but not explicitly 'disabled'
1522	// the behavior is the same, but the meaning is different, we are in default state off,
1523	// not user explictly setting us to off
1524	// NOTE: the real default ends up being set in IOHIDSystem::createParameters
1525	_stickyKeys_State				= 0;
1526
1527	_stickyKeys_NumModifiersDown	= 0;
1528
1529	// allocate shift toggle struct
1530	_stickyKeys_ShiftToggle = stickyKeysAllocToggleInfo (kNUM_SHIFTS_TO_ACTIVATE);
1531	if (_stickyKeys_ShiftToggle == NULL)
1532		return false;
1533
1534	// initialize shift toggle struct
1535	_stickyKeys_ShiftToggle->toggleModifier = NX_MODIFIERKEY_SHIFT;
1536	_stickyKeys_ShiftToggle->repetitionsToToggle = kNUM_SHIFTS_TO_ACTIVATE;
1537	clock_interval_to_absolutetime_interval( kDEFAULT_SHIFTEXPIREINTERVAL,
1538											kMillisecondScale,
1539											&_stickyKeys_ShiftToggle->expireInterval);
1540	_stickyKeys_ShiftToggle->currentCount = 0;
1541
1542	// allocate option toggle struct
1543	_stickyKeys_OptionToggle = stickyKeysAllocToggleInfo (kNUM_SHIFTS_TO_ACTIVATE);
1544	if (_stickyKeys_OptionToggle == NULL)
1545		return false;
1546
1547	// initialize option toggle struct
1548	_stickyKeys_OptionToggle->toggleModifier = NX_MODIFIERKEY_ALTERNATE;
1549	_stickyKeys_OptionToggle->repetitionsToToggle = kNUM_SHIFTS_TO_ACTIVATE;
1550	clock_interval_to_absolutetime_interval( kDEFAULT_SHIFTEXPIREINTERVAL,
1551											kMillisecondScale,
1552											&_stickyKeys_OptionToggle->expireInterval);
1553	_stickyKeys_OptionToggle->currentCount = 0;
1554
1555		_stickyKeysMouseClickEventSource = 0;
1556
1557		_stickyKeysSetFnStateEventSource = 0;
1558
1559	return createParamDicts();
1560}
1561
1562// stickyKeysfree
1563// free sticky keys variables
1564void IOHIKeyboardMapper::stickyKeysfree (void)
1565{
1566	// release shift toggle struct
1567	if (_stickyKeys_ShiftToggle)
1568		stickyKeysFreeToggleInfo(_stickyKeys_ShiftToggle);
1569
1570	// release option toggle struct
1571	if (_stickyKeys_OptionToggle)
1572		stickyKeysFreeToggleInfo(_stickyKeys_OptionToggle);
1573
1574	// release on param dict
1575	if (_onParamDict)
1576		_onParamDict->release();
1577
1578	// release off param dict
1579	if (_offParamDict)
1580		_offParamDict->release();
1581
1582    if (_reserved) {
1583		// release off fn param dict
1584		if (_offFnParamDict)
1585				_offFnParamDict->release();
1586
1587
1588		// release on fn param dict
1589		if (_onFnParamDict)
1590				_onFnParamDict->release();
1591
1592		if (_stickyKeysMouseClickEventSource) {
1593			_stickyKeysMouseClickEventSource->release();
1594			_stickyKeysMouseClickEventSource = 0;
1595		}
1596
1597		if (_stickyKeysSetFnStateEventSource) {
1598			_stickyKeysSetFnStateEventSource->release();
1599			_stickyKeysSetFnStateEventSource = 0;
1600		}
1601    }
1602}
1603
1604// allocate a StickyKeys_ToggleInfo struct
1605StickyKeys_ToggleInfo * IOHIKeyboardMapper::stickyKeysAllocToggleInfo (unsigned maxCount)
1606{
1607	StickyKeys_ToggleInfo *		toggleInfo;
1608	IOByteCount					size;
1609
1610	// size should be size of the structure plus
1611	// the size of each entry of the array (AbsoluteTime)
1612	// note the struct already has room for the first entry
1613	size = sizeof(StickyKeys_ToggleInfo) +
1614				(sizeof(AbsoluteTime) * (maxCount - 1));
1615
1616	// allocate shift toggle struct
1617	toggleInfo = (StickyKeys_ToggleInfo *)
1618		IOMalloc (size);
1619
1620	// set the size
1621	if (toggleInfo)
1622		toggleInfo->size = size;
1623
1624	return toggleInfo;
1625}
1626
1627// free a StickyKeys_ToggleInfo struct
1628void IOHIKeyboardMapper::stickyKeysFreeToggleInfo (StickyKeys_ToggleInfo * toggleInfo)
1629{
1630	// free shift toggle struct
1631	IOFree (toggleInfo, toggleInfo->size);
1632}
1633
1634// createParamDicts
1635// create on/off dicts as part of init
1636bool IOHIKeyboardMapper::createParamDicts ( void )
1637{
1638	bool	ok = true;
1639
1640	// create a dictionary that sets state to on
1641	_onParamDict = OSDictionary::withCapacity(4);
1642	if (_onParamDict)
1643	{
1644		// on
1645		makeNumberParamProperty( _onParamDict, kIOHIDStickyKeysOnKey,
1646					1, 32 );
1647	}
1648	else
1649		ok = false;
1650
1651	// create a dictionary that sets state to off
1652	if (ok)
1653		_offParamDict = OSDictionary::withCapacity(4);
1654	if (_offParamDict)
1655	{
1656		// off
1657		makeNumberParamProperty( _offParamDict, kIOHIDStickyKeysOnKey,
1658					0, 32 );
1659	}
1660	else
1661		ok = false;
1662
1663	// create a dictionary that sets fn state to on
1664	if (ok)
1665		_onFnParamDict = OSDictionary::withCapacity(4);
1666	if (_onFnParamDict)
1667	{
1668		// off
1669		makeNumberParamProperty( _onFnParamDict, kIOHIDFKeyModeKey,
1670					1, 32 );
1671
1672		_onFnParamDict->setObject(kIOHIDTemporaryParametersKey, kOSBooleanTrue);
1673	}
1674	else
1675		ok = false;
1676
1677	// create a dictionary that sets fn state to off
1678	if (ok)
1679		_offFnParamDict = OSDictionary::withCapacity(4);
1680	if (_offFnParamDict)
1681	{
1682		// off
1683		makeNumberParamProperty( _offFnParamDict, kIOHIDFKeyModeKey,
1684					0, 32 );
1685
1686		_offFnParamDict->setObject(kIOHIDTemporaryParametersKey, kOSBooleanTrue);
1687	}
1688	else
1689		ok = false;
1690
1691	return( ok );
1692}
1693
1694// postKeyboardSpecialEvent
1695// called to post special keyboard events
1696// thru the event system to outside of kernel clients
1697void	IOHIKeyboardMapper::postKeyboardSpecialEvent (unsigned subtype, unsigned eventType)
1698{
1699	_delegate->keyboardSpecialEvent (
1700				/* eventType */ eventType,
1701				/* flags */		_delegate->eventFlags(),
1702				/* keyCode */	NX_NOSPECIALKEY,
1703				/* specialty */ subtype);
1704}
1705
1706bool IOHIKeyboardMapper::stickyKeysModifierToggleCheck(StickyKeys_ToggleInfo    *toggleInfo,
1707                                                       UInt8                    key,
1708                                                       bool                     keyDown,
1709                                                       kbdBitVector             keyBits __unused,
1710                                                       bool                     mouseClick)
1711{
1712	unsigned char	thisBits = _parsedMapping.keyBits[key];
1713	int				index, innerindex;
1714	AbsoluteTime	now, deadline;
1715	bool			shouldToggle = false;
1716	unsigned			leftModBit = (thisBits & NX_WHICHMODMASK);
1717
1718		// Convert the modbit to left hand modifier
1719		convertToLeftModBit(leftModBit);
1720
1721	// is this the shift key?
1722	if ((leftModBit == toggleInfo->toggleModifier) && !mouseClick)
1723	{
1724		// get the time
1725		clock_get_uptime(&now);
1726
1727		// prune the list of all occurences whose deadline has expired
1728		// start at the end, which is the most recent shift
1729		for (index = toggleInfo->currentCount - 1; index >= 0; index--)
1730			// did this item's deadline expire?
1731			if (AbsoluteTime_to_scalar(&now) >
1732				AbsoluteTime_to_scalar(&toggleInfo->deadlines[index]))
1733			{
1734				// remove this shift and all shifts that occurred previously
1735
1736				// move all newer shifts to the start
1737				int entries_to_delete = index + 1;
1738
1739				for (innerindex = 0; innerindex < (int)(toggleInfo->currentCount - entries_to_delete); innerindex++)
1740					toggleInfo->deadlines[innerindex] =
1741						toggleInfo->deadlines[innerindex + entries_to_delete];
1742
1743				// update the count
1744				toggleInfo->currentCount -= entries_to_delete;
1745
1746				// defensive code
1747				index = -1;
1748
1749				// stop looping
1750				break;
1751			}
1752
1753		// is this a keydown, if so, add it to the list
1754		if (keyDown)
1755		{
1756			// we will add it if we have room
1757			if (toggleInfo->currentCount < toggleInfo->repetitionsToToggle)
1758			{
1759				// compute a new deadline
1760				clock_absolutetime_interval_to_deadline(toggleInfo->expireInterval, &deadline);
1761
1762				// add it
1763				toggleInfo->deadlines[toggleInfo->currentCount++] = deadline;
1764			}
1765		}
1766		// otherwise its a shift key up, if this the 5th one, then turn us on
1767		else
1768		{
1769			// is this the 5th shift
1770			if (toggleInfo->currentCount == toggleInfo->repetitionsToToggle)
1771			{
1772				// clear the list of shifts we are tracking
1773				toggleInfo->currentCount = 0;
1774
1775				// turn us on
1776				shouldToggle = true;
1777			}
1778		}
1779
1780	}
1781	// a non-shift key was used, start over timing the shift keys
1782	else
1783		toggleInfo->currentCount = 0;
1784
1785	return shouldToggle;
1786}
1787
1788// stickyKeysNonModifierKey
1789// called when a non-modifier key event occurs (up or down)
1790void IOHIKeyboardMapper::stickyKeysNonModifierKey(
1791								UInt8		 key,
1792								bool		 keyDown,
1793								kbdBitVector keyBits,
1794																bool		 mouseClick)
1795{
1796	int				index;
1797
1798	// first post this non-modifier key down
1799		if (!mouseClick)
1800			rawTranslateKeyCode(key, keyDown, keyBits);
1801
1802	// determine whether or not to post the keyups for the modifiers being held
1803	for (index = 0; index < _stickyKeys_NumModifiersDown; index++) {
1804			_stickyKeys_StuckModifiers[index].state |= kModifier_DidPerformModifiy;
1805
1806			// Has this key been keyed up.	If not, leave the key alone
1807			// because the user is still holding it down.
1808			if (((_stickyKeys_StuckModifiers[index].state & kModifier_DidKeyUp) != 0) &&
1809				((_stickyKeys_StuckModifiers[index].state & kModifier_Locked) == 0)) {
1810				// We keyed up ealier, so we should call stickyKeysModifierKey to
1811				// individually release the key
1812				stickyKeysModifierKey(_stickyKeys_StuckModifiers[index].key, false, keyBits);
1813
1814				// We basically took a modifier off the list, so we have to decrement
1815				// our local index
1816				index --;
1817			}
1818		}
1819
1820	// clear state, if modifiers no longer down
1821		if (_stickyKeys_NumModifiersDown == 0)
1822			_stickyKeys_State &= ~kState_On_ModifiersDown;
1823
1824}
1825
1826// stickyKeysModifierKey
1827// called when shift/command/control/option key goes down
1828// returns true if the key should be processed
1829bool IOHIKeyboardMapper::stickyKeysModifierKey(
1830							UInt8		 key,
1831							bool		 keyDown,
1832							kbdBitVector keyBits)
1833{
1834	unsigned char	thisBits	= _parsedMapping.keyBits[key];
1835	int			index		= 0;
1836	int			innerindex	= 0;
1837	bool		isBeingHeld = false;
1838	bool		shouldBeHandled = true;
1839	int			heldIndex	= 0;
1840	int			leftModBit	= (thisBits & NX_WHICHMODMASK);
1841
1842		// Convert the modbit to left hand modifier
1843		convertToLeftModBit(leftModBit);
1844
1845	// is this key being held? (if so, dont post the down)
1846	isBeingHeld = false;
1847	for (index = 0; index < _stickyKeys_NumModifiersDown; index++)
1848		if (_stickyKeys_StuckModifiers[index].leftModBit == leftModBit)
1849		{
1850			isBeingHeld = true;
1851			heldIndex = index;
1852
1853			// break out of loop, modifers will not be in twice
1854			break;
1855		}
1856
1857	// The following condition has been added, so that chording of key combinations can be supported
1858	if (! keyDown) {
1859				// For chording, we only care if the modifier is being held
1860				if (isBeingHeld)
1861				{
1862							if (((_stickyKeys_StuckModifiers[heldIndex].state & kModifier_DidPerformModifiy) != 0) &&
1863								((_stickyKeys_StuckModifiers[heldIndex].state & kModifier_Locked) == 0)) {
1864									// This modifier keyed up, but it also modified a key.
1865									// Therefore it needs to be released.
1866									goto RELEASE_STICKY_MODIFIER_KEY;
1867							}
1868							else
1869							{
1870									// set the state flag, so that stickyKeysNonModifierKey can call
1871									// back into this function to release the key.
1872									_stickyKeys_StuckModifiers[heldIndex].state |= kModifier_DidKeyUp;
1873
1874									if (((thisBits & NX_WHICHMODMASK) == NX_MODIFIERKEY_SECONDARYFN) &&
1875										((_stickyKeys_State & kState_StickyFnKeyStateChangePending) != 0))
1876									{
1877										_stickyKeys_State &= ~kState_StickyFnKeyStateChangePending;
1878
1879										if (_stickyKeysSetFnStateEventSource)
1880											_stickyKeysSetFnStateEventSource->interruptOccurred(0, 0, 0);
1881									}
1882							}
1883				}
1884				// RY: take care of the case where the modifier was held down
1885				// prior to starting sticky keys.  The key up will let be
1886				// processed as normal.
1887				else
1888					shouldBeHandled = false;
1889		}
1890		// we have a key down
1891		else
1892		{
1893				// is this key being held? (if so, stop holding it - toggle off)
1894		if (isBeingHeld)
1895		{
1896
1897					// If this key has been locked, then it needs to be release
1898					// The third and final state of the modifier key
1899					if ((_stickyKeys_StuckModifiers[heldIndex].state & kModifier_Locked) != 0)
1900					{
1901RELEASE_STICKY_MODIFIER_KEY:
1902			// stop holding this key down
1903
1904			// post the key up
1905			rawTranslateKeyCode(_stickyKeys_StuckModifiers[heldIndex].key, false, keyBits);
1906
1907			// clear this one (handles the case this is the last key held)
1908			_stickyKeys_StuckModifiers[heldIndex].key = 0;
1909						_stickyKeys_StuckModifiers[heldIndex].state = 0;
1910						_stickyKeys_StuckModifiers[heldIndex].leftModBit = 0;
1911
1912			// reduce our global count
1913			// (do this before the loop, so loop does not overrun)
1914			_stickyKeys_NumModifiersDown--;
1915
1916			// if no more keys being held, clear our state
1917			if (_stickyKeys_NumModifiersDown == 0)
1918				_stickyKeys_State &= ~kState_On_ModifiersDown;
1919
1920			// move each item after this one forward
1921			// note, _stickyKeys_NumModifiersDown already decremented
1922			for (innerindex = heldIndex; innerindex < _stickyKeys_NumModifiersDown; innerindex++) {
1923				_stickyKeys_StuckModifiers[innerindex].key = _stickyKeys_StuckModifiers[innerindex + 1].key;
1924								_stickyKeys_StuckModifiers[innerindex].state = _stickyKeys_StuckModifiers[innerindex + 1].state;
1925								_stickyKeys_StuckModifiers[innerindex].leftModBit = _stickyKeys_StuckModifiers[innerindex + 1].leftModBit;
1926						}
1927
1928						// notify the world we changed
1929						// note, we send a new event every time the user releses the modifier
1930						// while we are still holding modifiers. Clients must know to expect this
1931						switch ((thisBits & NX_WHICHMODMASK))
1932						{
1933							case NX_MODIFIERKEY_SHIFT:
1934							case NX_MODIFIERKEY_RSHIFT:
1935								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_SHIFT_UP);
1936								break;
1937							case NX_MODIFIERKEY_CONTROL:
1938							case NX_MODIFIERKEY_RCONTROL:
1939								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_CONTROL_UP);
1940								break;
1941							case NX_MODIFIERKEY_ALTERNATE:
1942							case NX_MODIFIERKEY_RALTERNATE:
1943								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_ALTERNATE_UP);
1944								break;
1945							case NX_MODIFIERKEY_COMMAND:
1946							case NX_MODIFIERKEY_RCOMMAND:
1947								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_COMMAND_UP);
1948								break;
1949							case NX_MODIFIERKEY_SECONDARYFN:
1950								// Since we most likely running via IOHIDSystem::cmdGate runAction,
1951								// we should really trigger an interrupt to run this later on the
1952								// workloop.  This will also avoid any synchronization anomolies.
1953								_stickyKeys_State &= ~(kState_StickyFnKeyStateOn | kState_StickyFnKeyStateChangePending);
1954
1955								if (_stickyKeysSetFnStateEventSource)
1956									_stickyKeysSetFnStateEventSource->interruptOccurred(0, 0, 0);
1957
1958								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_FN_UP);
1959								break;
1960							default:
1961								break;
1962						}
1963
1964					}
1965
1966					// This is the second press, therefore this key needs to be locked.
1967					else
1968					{
1969						_stickyKeys_StuckModifiers[heldIndex].state |= kModifier_Locked;
1970
1971						// notify the world we changed
1972						// note, we send a new event every time the user releses the modifier
1973						// while we are still holding modifiers. Clients must know to expect this
1974						switch ((thisBits & NX_WHICHMODMASK))
1975						{
1976							case NX_MODIFIERKEY_SHIFT:
1977							case NX_MODIFIERKEY_RSHIFT:
1978								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_SHIFT_LOCK);
1979								break;
1980							case NX_MODIFIERKEY_CONTROL:
1981							case NX_MODIFIERKEY_RCONTROL:
1982								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_CONTROL_LOCK);
1983								break;
1984							case NX_MODIFIERKEY_ALTERNATE:
1985							case NX_MODIFIERKEY_RALTERNATE:
1986								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_ALTERNATE_LOCK);
1987								break;
1988							case NX_MODIFIERKEY_COMMAND:
1989							case NX_MODIFIERKEY_RCOMMAND:
1990								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_COMMAND_LOCK);
1991								break;
1992							case NX_MODIFIERKEY_SECONDARYFN:
1993								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_FN_LOCK);
1994								break;
1995							default:
1996								break;
1997						}
1998
1999					}
2000				}
2001
2002				// if this key is not being held already, then post the modifier down
2003		else
2004		{
2005						rawTranslateKeyCode(key, keyDown, keyBits);
2006
2007			// and remember it is down
2008			if (_stickyKeys_NumModifiersDown < kMAX_MODIFIERS) {
2009								int modifierIndex = _stickyKeys_NumModifiersDown++;
2010				_stickyKeys_StuckModifiers[modifierIndex].key = key;
2011								_stickyKeys_StuckModifiers[modifierIndex].state = 0;
2012								_stickyKeys_StuckModifiers[modifierIndex].leftModBit = leftModBit;
2013						}
2014			else
2015				;	// add a system log error here?
2016
2017			// change our state
2018			_stickyKeys_State |= kState_On_ModifiersDown;
2019
2020
2021						// notify the world we changed
2022						// note, we send a new event every time the user releses the modifier
2023						// while we are still holding modifiers. Clients must know to expect this
2024						switch ((thisBits & NX_WHICHMODMASK))
2025						{
2026							case NX_MODIFIERKEY_SHIFT:
2027							case NX_MODIFIERKEY_RSHIFT:
2028								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_SHIFT_DOWN);
2029								break;
2030							case NX_MODIFIERKEY_CONTROL:
2031							case NX_MODIFIERKEY_RCONTROL:
2032								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_CONTROL_DOWN);
2033								break;
2034							case NX_MODIFIERKEY_ALTERNATE:
2035							case NX_MODIFIERKEY_RALTERNATE:
2036								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_ALTERNATE_DOWN);
2037								break;
2038							case NX_MODIFIERKEY_COMMAND:
2039							case NX_MODIFIERKEY_RCOMMAND:
2040								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_COMMAND_DOWN);
2041								break;
2042							case NX_MODIFIERKEY_SECONDARYFN:
2043								// Since we most likely running via IOHIDSystem::cmdGate runAction,
2044								// we should really trigger an interrupt to run this later on the
2045								// workloop.  This will also avoid any synchronization anomolies.
2046								_stickyKeys_State |= kState_StickyFnKeyStateOn | kState_StickyFnKeyStateChangePending;
2047
2048								postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_FN_DOWN);
2049								break;
2050							default:
2051								break;
2052						}
2053
2054		}
2055	}
2056		return shouldBeHandled;
2057}
2058
2059
2060// stickyKeysFilterKey
2061// returns true if this key event should be ignored
2062// It may call rawTranslateKeyCode multiple times to generate keyups
2063// at the end of a sticky keys sequence
2064// this function is the essence of the sticky keys feature
2065
2066bool IOHIKeyboardMapper::stickyKeysFilterKey(
2067							UInt8		 key,
2068							bool		 keyDown,
2069							kbdBitVector keyBits,
2070							bool		 mouseClick)
2071{
2072	unsigned char	thisBits = _parsedMapping.keyBits[key];
2073	bool			shouldFilter = false;
2074	bool			shouldToggleState = false;
2075
2076	if ( _parsedMapping.maxMod == -1 )
2077		return false;
2078
2079	// if we are disabled, then do nothing
2080	if ((_stickyKeys_State & kState_Disabled_Flag) != 0)
2081		return false;
2082
2083	// check to see if option key toggle activated
2084	// only do so if the shift toggles bit is set
2085	// we could have a seperate bit to set whether option
2086	// should send the event, but we dont. Since the UI
2087	// uses these to be one in the same, we will as well.
2088	if ((_stickyKeys_State & kState_ShiftActivates_Flag) != 0)
2089	{
2090		// check to see if shift key pressed, possible to toggle state
2091		shouldToggleState = stickyKeysModifierToggleCheck
2092									(_stickyKeys_ShiftToggle, key, keyDown, keyBits, mouseClick);
2093	}
2094
2095	if ((_stickyKeys_State & kState_OptionActivates_Flag) != 0)
2096	{
2097		// if the option was toggled
2098		if (stickyKeysModifierToggleCheck (_stickyKeys_OptionToggle,key, keyDown, keyBits, mouseClick))
2099				// if so, send the event to toggle mouse driving
2100				postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_TOGGLEMOUSEDRIVING);
2101	}
2102
2103	// if we are on and holding modifier keys and we have a key down, finish if this is not modifier
2104	if (((_stickyKeys_State & kState_On_ModifiersDown) != 0) && !modifierOfInterest(thisBits))
2105	{
2106		// Make sure that this is not a key and not a modifier that we track
2107		// This will allow us to pass through other modifiers like the arrow keys
2108		if (mouseClick ||
2109			(keyDown && !(((_stickyKeys_State & kState_MouseKeyStateOn) != 0) && mouseKey(thisBits))) ||
2110			(!keyDown && !(((_stickyKeys_State & kState_MouseKeyStateOn) != 0) && mouseKeyToIgnore(thisBits, key))) )
2111		{
2112			// we will handle all the events here, so dont process this one normally
2113			shouldFilter = true;
2114
2115			// handle non-modifer key
2116			stickyKeysNonModifierKey (key, keyDown, keyBits, mouseClick);
2117		}
2118
2119	}
2120
2121	// if we are on and looking for modifier keys, see if this is one
2122	if ((_stickyKeys_State & kState_On) != 0)
2123	{
2124
2125		// set up interrupt event source for to handle sticky mouse down
2126		if (!_stickyKeysMouseClickEventSource && _hidSystem)
2127		{
2128			_stickyKeysMouseClickEventSource =
2129				IOInterruptEventSource::interruptEventSource
2130				(this, (IOInterruptEventSource::Action) stickyKeysMouseUp);
2131
2132			if(_stickyKeysMouseClickEventSource &&
2133				(_hidSystem->getWorkLoop()->addEventSource(_stickyKeysMouseClickEventSource) != kIOReturnSuccess)) {
2134				_stickyKeysMouseClickEventSource->release();
2135				_stickyKeysMouseClickEventSource = 0;
2136			}
2137		}
2138
2139		// set up interrup event source to handle sticky fn state
2140		if (!_stickyKeysSetFnStateEventSource && _hidSystem)
2141		{
2142			_stickyKeysSetFnStateEventSource =
2143				IOInterruptEventSource::interruptEventSource
2144				(this, (IOInterruptEventSource::Action) stickyKeysSetFnState);
2145
2146			if(_stickyKeysSetFnStateEventSource &&
2147				(_hidSystem->getWorkLoop()->addEventSource(_stickyKeysSetFnStateEventSource) != kIOReturnSuccess)) {
2148				_stickyKeysSetFnStateEventSource->release();
2149				_stickyKeysSetFnStateEventSource = 0;
2150			}
2151		}
2152
2153		// is this a sticky keys modifier key?
2154		// is this a modifier?
2155		if (modifierOfInterest(thisBits))
2156		{
2157			// we will handle all the events here, so dont process this one normally
2158			// RY: stickyKeysModifierKey will return false if the key was held down
2159			// prior to turning on stickykeys.
2160			shouldFilter = stickyKeysModifierKey (key, keyDown, keyBits);
2161
2162		}
2163	}
2164
2165	// if we are supposed to toggle our state, do it now
2166	if (shouldToggleState)
2167	{
2168		// if we were on, clear a few things going off
2169		if ((_stickyKeys_State & kState_On) != 0)
2170		{
2171			stickyKeysCleanup();
2172			postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_OFF);
2173		}
2174		else
2175		{
2176			_stickyKeys_State |= kState_On;
2177			postKeyboardSpecialEvent (NX_SUBTYPE_STICKYKEYS_ON);
2178		}
2179
2180		// remember we changed
2181		_stateDirty = true;
2182
2183		// Since we most likely running via IOHIDSystem::cmdGate runAction,
2184		// we should really trigger an interrupt to run this later on the
2185		// workloop.  This will also avoid any synchronization anomolies.
2186		if (_stickyKeysSetFnStateEventSource)
2187			_stickyKeysSetFnStateEventSource->interruptOccurred(0, 0, 0);
2188	}
2189
2190	return shouldFilter;
2191}
2192
2193void IOHIKeyboardMapper::stickyKeysCleanup()
2194{
2195	_stickyKeys_State &= ~kState_On;
2196
2197	// post the keyups for all the modifier keys being held
2198	for (int index = 0; index < _stickyKeys_NumModifiersDown; index++)
2199		rawTranslateKeyCode(_stickyKeys_StuckModifiers[index].key, false, _cached_KeyBits);
2200
2201	// clear state, modifiers no longer down
2202	_stickyKeys_State &= ~kState_On_ModifiersDown;
2203	_stickyKeys_NumModifiersDown = 0;
2204
2205	// clear the fn key state
2206	_stickyKeys_State &= ~kState_StickyFnKeyStateOn;
2207
2208	// Since we most likely running via IOHIDSystem::cmdGate runAction,
2209	// we should really trigger an interrupt to run this later on the
2210	// workloop.  This will also avoid any synchronization anomolies.
2211	if (_stickyKeysSetFnStateEventSource)
2212		_stickyKeysSetFnStateEventSource->interruptOccurred(0, 0, 0);
2213
2214}
2215
2216void IOHIKeyboardMapper::keyEventPostProcess (void)
2217{
2218	bool			nowOn;
2219	OSDictionary *	dict;
2220
2221	// if the state changed
2222	if (_stateDirty)
2223	{
2224		// if we have a valid IOHIDSystem
2225		if (_hidSystem)
2226		{
2227			// are we now on?
2228			nowOn = ((_stickyKeys_State & kState_On) != 0);
2229
2230			// choose the proper dictionary
2231			dict = nowOn ? _onParamDict : _offParamDict;
2232
2233			// set it
2234			_hidSystem->setParamProperties (dict);
2235		}
2236
2237		// no longer dirty
2238		// (the case of a NULL _hidSystem should not happen, so
2239		//	no point in maintaining a dirty state till one shows up)
2240		_stateDirty = false;
2241	}
2242
2243}
2244
2245
2246
2247// F12 Eject member functions
2248
2249// f12EjectFilterKey
2250// This function will determine whether or not f12 was pressed.
2251// If held down for a predetermined amount of time and eject
2252// notification will be issued.	 If key release early, this method
2253// will call rawTranslateKeyCode for keyDown and return false.
2254
2255bool IOHIKeyboardMapper::f12EjectFilterKey (UInt8 key, bool keyDown, kbdBitVector keyBits) {
2256
2257	// Check the delay time.  If 0, then the feature is off.
2258	if ((_eject_Delay_MS == 0) || !_supportsF12Eject )
2259		return false;
2260
2261	if (key == kADB_KEYBOARD_F12) {
2262
2263		// Let's check to see if an IOTimerEventSource exists.
2264		// If not, create one.
2265		if (!_ejectTimerEventSource) {
2266			// Make sure we have an instance of _hidSystem.
2267			if (_hidSystem == NULL)
2268				return false;
2269
2270			_ejectTimerEventSource = IOTimerEventSource::timerEventSource
2271										(this, (IOTimerEventSource::Action) &IOHIKeyboardMapper::performF12Eject);
2272
2273			if (_hidSystem->getWorkLoop()->addEventSource(_ejectTimerEventSource) != kIOReturnSuccess)
2274				return false;
2275
2276		}
2277
2278		if (keyDown == true) {
2279			// Set the time out and the flag
2280			_f12Eject_State |= kState_In_Progess_Flag;
2281
2282			_ejectTimerEventSource->setTimeoutMS(_eject_Delay_MS);
2283
2284			return true;  // prevent processing of f12
2285
2286		} else {
2287
2288			// If the user pulled out early, send a key down event.
2289			// Since we return false, the system will take care of the
2290			// key up.
2291			if ((_f12Eject_State & kState_In_Progess_Flag) != 0) {
2292
2293				_ejectTimerEventSource->cancelTimeout();
2294
2295				_f12Eject_State &= ~kState_In_Progess_Flag;
2296
2297				rawTranslateKeyCode (key, true, keyBits);
2298			}
2299
2300			// If we get to this point, the eject happened.
2301			// Therefore we should ignore the key up.
2302			else
2303				return true;
2304
2305		}
2306	}
2307
2308	// I think we should process all other key events during this check.
2309	// That is why I'm returning false;
2310
2311	return false;
2312
2313}
2314
2315// performF12Eject
2316// This is a static method called by the ejectTimerEventSource.
2317// It will send an System eject event
2318
2319void IOHIKeyboardMapper::performF12Eject(IOHIKeyboardMapper *owner, IOTimerEventSource *sender __unused) {
2320
2321	// Post the eject keydown event.
2322	owner->postKeyboardSpecialEvent(NX_KEYTYPE_EJECT, NX_KEYDOWN);
2323
2324	// Clear the state
2325	owner->_f12Eject_State &= ~kState_In_Progess_Flag;
2326
2327}
2328
2329// Slowkeys member functions
2330
2331// slowKeysFilterKey
2332// This function will determine whether or not a a key need to be
2333// processed for the slow keys feature.	 If so, if a key is held
2334// down for a predetermined amount of time, a key down will be
2335// pushed on up to the HID System.	Other scenarios to the state
2336// machine are documented in further detail below.
2337
2338bool IOHIKeyboardMapper::slowKeysFilterKey (UInt8 key, bool keyDown, kbdBitVector keyBits __unused)
2339{
2340	bool returnValue = true;
2341
2342	if (_slowKeys_Delay_MS == 0)
2343		return false;
2344
2345	// Let's check to see if an IOTimerEventSource exists.
2346	// If not, create one.
2347	if (!_slowKeysTimerEventSource) {
2348
2349		// Make sure we have an instance of _hidSystem.
2350		if (_hidSystem == NULL)
2351			return false;
2352
2353		_slowKeysTimerEventSource = IOTimerEventSource::timerEventSource
2354									(this, (IOTimerEventSource::Action) &IOHIKeyboardMapper::slowKeysPostProcess );
2355
2356
2357		if(_hidSystem->getWorkLoop()->addEventSource(_slowKeysTimerEventSource) != kIOReturnSuccess)
2358			return false;
2359
2360	}
2361
2362
2363	if (keyDown) {
2364		// Ladies and Gentlemen start your engines
2365		if ((_slowKeys_State & kState_In_Progess_Flag) == 0) {
2366
2367			// Check to see if we are currently handling a repeated key.
2368			// If so, and the key pressed differs from the key that is
2369			// being repeated post the key up for that repeated key and
2370			// clear the flag.
2371			if ((key != _slowKeys_Current_Key) && ((_slowKeys_State & kState_Is_Repeat_Flag) != 0)) {
2372
2373				postSlowKeyTranslateKeyCode(this, _slowKeys_Current_Key, false, _cached_KeyBits);
2374
2375				_slowKeys_State &= ~kState_Is_Repeat_Flag;
2376			}
2377
2378			// Start the normal processing.
2379
2380			_slowKeys_State |= kState_In_Progess_Flag;
2381
2382			_slowKeys_Current_Key = key;
2383
2384			_slowKeysTimerEventSource->setTimeoutMS(_slowKeys_Delay_MS);
2385
2386			// Set a state flag telling us that the key is being repeated.
2387			if (_delegate->isRepeat())
2388				_slowKeys_State |= kState_Is_Repeat_Flag;
2389
2390			// Notify System that this is the start
2391			postKeyboardSpecialEvent(NX_SUBTYPE_SLOWKEYS_START);
2392		}
2393
2394		// if another key goes down while in progress, start abort process
2395		else if (((_slowKeys_State & kState_In_Progess_Flag) != 0) && (key != _slowKeys_Current_Key)) {
2396
2397			_slowKeysTimerEventSource->cancelTimeout();
2398
2399			_slowKeys_State |= kState_Aborted_Flag;
2400			_slowKeys_State &= ~kState_In_Progess_Flag;
2401
2402			_slowKeys_Aborted_Key = key;
2403
2404			// If the slow key is being repeated, send a key up
2405			// for that key and clear the flag
2406			if ((_slowKeys_State & kState_Is_Repeat_Flag) != 0) {
2407
2408				postSlowKeyTranslateKeyCode(this, _slowKeys_Current_Key, false, _cached_KeyBits);
2409
2410				_slowKeys_State &= ~kState_Is_Repeat_Flag;
2411			}
2412
2413			// Notify System that this is an abort
2414			postKeyboardSpecialEvent(NX_SUBTYPE_SLOWKEYS_ABORT);
2415		}
2416	}
2417
2418	// handing for a key up
2419	else {
2420
2421		if (key == _slowKeys_Current_Key) {
2422
2423			// If the current key come up while in progress, kill it
2424			if ((_slowKeys_State & kState_In_Progess_Flag) != 0) {
2425
2426				_slowKeysTimerEventSource->cancelTimeout();
2427				_slowKeys_State &= ~kState_In_Progess_Flag;
2428
2429				// If the key is being repeated, pass the key up through
2430				// and clear the flag
2431				if ((_slowKeys_State & kState_Is_Repeat_Flag) != 0) {
2432
2433					_slowKeys_State &= ~kState_Is_Repeat_Flag;
2434
2435					returnValue = false;
2436				}
2437			}
2438
2439			// Otherwise, if the key was not aborted, pass the key up through
2440			else if ((_slowKeys_State & kState_Aborted_Flag) == 0) {
2441
2442				// Clear the flag if this was a repeated key
2443				if ((_slowKeys_State & kState_Is_Repeat_Flag) != 0)
2444					_slowKeys_State &= ~kState_Is_Repeat_Flag;
2445
2446				returnValue = false;
2447			}
2448		}
2449
2450		// If the key that caused an abort comes up, it will kill any current slowkeys action
2451		else if ((key == _slowKeys_Aborted_Key) && ((_slowKeys_State & kState_Aborted_Flag) != 0)){
2452
2453			_slowKeysTimerEventSource->cancelTimeout();
2454
2455			_slowKeys_State &= ~kState_Aborted_Flag;
2456			_slowKeys_State &= ~kState_In_Progess_Flag;
2457
2458			// If the slow key is being repeated, send a key up for the slow key
2459			// and clear the flag
2460			if ((_slowKeys_State & kState_Is_Repeat_Flag) != 0) {
2461
2462				postSlowKeyTranslateKeyCode(this, _slowKeys_Current_Key, false, _cached_KeyBits);
2463
2464				_slowKeys_State &= ~kState_Is_Repeat_Flag;
2465			}
2466
2467			// Notify System that this is an abort
2468			postKeyboardSpecialEvent(NX_SUBTYPE_SLOWKEYS_ABORT);
2469		}
2470
2471		// This key has already been processed/	 Pass the key up through
2472		else {
2473
2474			returnValue = false;
2475		}
2476	}
2477
2478	return returnValue;
2479}
2480
2481// slowKeysPostProcess
2482
2483// This is a IOTimerEventSource::Action.
2484// It is responsible for sending a key down
2485// to the HID System.
2486
2487void IOHIKeyboardMapper::slowKeysPostProcess (IOHIKeyboardMapper *owner, IOTimerEventSource *sender __unused)
2488{
2489	owner->_slowKeys_State &= ~kState_In_Progess_Flag;
2490
2491	// Post the key down
2492	postSlowKeyTranslateKeyCode(owner, owner->_slowKeys_Current_Key, true, owner->_cached_KeyBits);
2493
2494	// Notify System that this is the end
2495	owner->postKeyboardSpecialEvent(NX_SUBTYPE_SLOWKEYS_END);
2496}
2497
2498void IOHIKeyboardMapper::stickyKeysSetFnState(IOHIKeyboardMapper *owner, IOEventSource *sender __unused)
2499{
2500	OSDictionary *dict;
2501
2502	if ((owner->_stickyKeys_State & kState_On) != 0)
2503	{
2504		dict = (((owner->_stickyKeys_State & kState_PrefFnKeyStateOn) != 0) ^ ((owner->_stickyKeys_State & kState_StickyFnKeyStateOn) != 0)) ?
2505				owner->_onFnParamDict : owner->_offFnParamDict;
2506	}
2507	else
2508	{
2509		dict = ((owner->_stickyKeys_State & kState_PrefFnKeyStateOn) != 0) ? owner->_onFnParamDict : owner->_offFnParamDict;
2510	}
2511
2512	owner->_hidSystem->setParamProperties (dict);
2513}
2514
2515void IOHIKeyboardMapper::stickyKeysMouseUp(IOHIKeyboardMapper *owner, IOEventSource *sender __unused)
2516{
2517	owner->stickyKeysFilterKey (0, 0, owner->_cached_KeyBits, true);
2518}
2519
2520OSMetaClassDefineReservedUsed(IOHIKeyboardMapper,  0);
2521IOReturn IOHIKeyboardMapper::message( UInt32 type, IOService * provider __unused, void * argument __unused )
2522{
2523
2524	switch (type)
2525	{
2526		case kIOHIDSystem508MouseClickMessage:
2527		case kIOHIDSystem508SpecialKeyDownMessage:
2528
2529			// Since we most likely running via IOHIDSystem::cmdGate runAction,
2530			// we should really trigger an interrupt to run this later on the
2531			// workloop.  This will also avoid any synchronization anomolies.
2532			if (_stickyKeysMouseClickEventSource)
2533				_stickyKeysMouseClickEventSource->interruptOccurred(0, 0, 0);
2534
2535			break;
2536
2537		default:
2538			break;
2539	}
2540	return kIOReturnSuccess;
2541}
2542OSMetaClassDefineReservedUnused(IOHIKeyboardMapper,	 1);
2543OSMetaClassDefineReservedUnused(IOHIKeyboardMapper,	 2);
2544OSMetaClassDefineReservedUnused(IOHIKeyboardMapper,	 3);
2545OSMetaClassDefineReservedUnused(IOHIKeyboardMapper,	 4);
2546OSMetaClassDefineReservedUnused(IOHIKeyboardMapper,	 5);
2547OSMetaClassDefineReservedUnused(IOHIKeyboardMapper,	 6);
2548OSMetaClassDefineReservedUnused(IOHIKeyboardMapper,	 7);
2549OSMetaClassDefineReservedUnused(IOHIKeyboardMapper,	 8);
2550OSMetaClassDefineReservedUnused(IOHIKeyboardMapper,	 9);
2551OSMetaClassDefineReservedUnused(IOHIKeyboardMapper, 10);
2552OSMetaClassDefineReservedUnused(IOHIKeyboardMapper, 11);
2553OSMetaClassDefineReservedUnused(IOHIKeyboardMapper, 12);
2554OSMetaClassDefineReservedUnused(IOHIKeyboardMapper, 13);
2555OSMetaClassDefineReservedUnused(IOHIKeyboardMapper, 14);
2556OSMetaClassDefineReservedUnused(IOHIKeyboardMapper, 15);
2557