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