2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 * From EventSrcPCKeyoard.m - PC Keyboard EventSrc subclass implementation
25 * Copyright (c) 1992 NeXT Computer, Inc. All rights reserved.
26 * 20-Dec-00 bubba Save global repeat and delay values when
27 * devices are unplugged. Restore when device is reset.
28 * 24-Jan-01 bubba Don't auto-repeat on Power Key. This prevents infinite power key
29 * events from being generated when this key is hit on ADB keyboards.
32 #include <IOKit/IOLib.h>
33 #include <IOKit/hidsystem/IOHIKeyboard.h>
34 #include <IOKit/hidsystem/IOHIKeyboardMapper.h>
35 #include <IOKit/hidsystem/IOLLEvent.h>
36 #include <IOKit/hidsystem/IOHIDParameter.h>
38 AbsoluteTime gKeyRepeat
= { 0 }; // Delay between key repeats
39 AbsoluteTime gInitialKeyRepeat
= { 0 }; // Delay before initial key repeat
41 #define super IOHIDevice
42 OSDefineMetaClassAndStructors(IOHIKeyboard
, IOHIDevice
);
44 bool IOHIKeyboard::init(OSDictionary
* properties
)
46 if (!super::init(properties
)) return false;
49 * Initialize minimal state.
52 _deviceLock
= IOLockAlloc();
54 _keyStateSize
= 4*((maxKeyCodes()+(EVK_BITS_PER_UNIT
-1))/EVK_BITS_PER_UNIT
);
55 _keyState
= (UInt32
*) IOMalloc(_keyStateSize
);
57 if (!_deviceLock
|| !_keyState
) return false;
59 IOLockInit(_deviceLock
);
60 bzero(_keyState
, _keyStateSize
);
65 bool IOHIKeyboard::start(IOService
* provider
)
67 if (!super::start(provider
)) return false;
70 * IOHIKeyboard serves both as a service and a nub (we lead a double
71 * life). Register ourselves as a nub to kick off matching.
79 void IOHIKeyboard::free()
80 // Description: Go Away. Be careful when freeing the lock.
84 // Save repeat rate and delay, so when we are replugged we'll be ready
85 // with the right values.
87 gKeyRepeat
= _keyRepeat
;
88 gInitialKeyRepeat
= _initialKeyRepeat
;
99 IOFree( _keyState
, _keyStateSize
);
108 IOHIDKind
IOHIKeyboard::hidKind()
110 return kHIKeyboardDevice
;
113 bool IOHIKeyboard::updateProperties( void )
115 UInt64 keyRepeatNano
;
116 UInt64 initialKeyRepeatNano
;
119 absolutetime_to_nanoseconds( _keyRepeat
, &keyRepeatNano
);
120 absolutetime_to_nanoseconds( _initialKeyRepeat
, &initialKeyRepeatNano
);
122 ok
= setProperty( kIOHIDKeyMappingKey
, _keyMap
)
123 & setProperty( kIOHIDKeyRepeatKey
, &keyRepeatNano
,
124 sizeof(keyRepeatNano
))
125 & setProperty( kIOHIDInitialKeyRepeatKey
, &initialKeyRepeatNano
,
126 sizeof(initialKeyRepeatNano
));
128 return( ok
& super::updateProperties() );
131 IOReturn
IOHIKeyboard::setParamProperties( OSDictionary
* dict
)
134 IOReturn err
= kIOReturnSuccess
;
136 IOHIKeyboardMapper
* oldMap
;
137 bool updated
= false;
139 IOTakeLock( _deviceLock
);
141 if( (data
= OSDynamicCast( OSData
,
142 dict
->getObject(kIOHIDKeyRepeatKey
)))) {
144 nano
= *((UInt64
*)(data
->getBytesNoCopy()));
145 if( nano
< EV_MINKEYREPEAT
)
146 nano
= EV_MINKEYREPEAT
;
147 nanoseconds_to_absolutetime(nano
, &_keyRepeat
);
151 if( (data
= OSDynamicCast( OSData
,
152 dict
->getObject(kIOHIDInitialKeyRepeatKey
)))) {
154 nano
= *((UInt64
*)(data
->getBytesNoCopy()));
155 if( nano
< EV_MINKEYREPEAT
)
156 nano
= EV_MINKEYREPEAT
;
157 nanoseconds_to_absolutetime(nano
, &_initialKeyRepeat
);
161 if( (data
= OSDynamicCast( OSData
, dict
->getObject(kIOHIDKeyMappingKey
)))) {
163 map
= (unsigned char *)IOMalloc( data
->getLength() );
164 bcopy( data
->getBytesNoCopy(), map
, data
->getLength() );
166 _keyMap
= IOHIKeyboardMapper::keyboardMapper(this, map
, data
->getLength(), true);
173 err
= kIOReturnBadArgument
;
176 IOUnlock( _deviceLock
);
178 if( dict
->getObject(kIOHIDResetKeyboardKey
))
187 bool IOHIKeyboard::resetKeyboard()
188 // Description: Reset the keymapping to the default value and reconfigure
191 const unsigned char *defaultKeymap
;
192 UInt32 defaultKeymapLength
;
194 IOTakeLock( _deviceLock
);
199 // Set up default keymapping.
200 defaultKeymap
= defaultKeymapOfLength(&defaultKeymapLength
);
202 _keyMap
= IOHIKeyboardMapper::keyboardMapper( this,
208 clock_interval_to_absolutetime_interval( EV_DEFAULTKEYREPEAT
,
209 kNanosecondScale
, &_keyRepeat
);
210 clock_interval_to_absolutetime_interval( EV_DEFAULTINITIALREPEAT
,
211 kNanosecondScale
, &_initialKeyRepeat
);
214 // Use our globals if valid. That way, if we are unplugged and replugged, we'll
215 // have the proper values, instead of the lame default values.
217 if( gKeyRepeat
.lo
> 0 ) _keyRepeat
= gKeyRepeat
;
218 if( gInitialKeyRepeat
.lo
> 0 ) _initialKeyRepeat
= gInitialKeyRepeat
;
222 _interfaceType
= interfaceID();
223 _deviceType
= deviceType();
226 IOUnlock( _deviceLock
);
227 return (_keyMap
) ? true : false;
230 void IOHIKeyboard::scheduleAutoRepeat()
231 // Description: Schedule a procedure to be called when a timeout has expired
232 // so that we can generate a repeated key.
234 // * _deviceLock should be held on entry
236 if ( _calloutPending
== true )
238 thread_call_func_cancel(_autoRepeat
, this, true);
239 _calloutPending
= false;
241 if ( AbsoluteTime_to_scalar(&_downRepeatTime
) )
243 AbsoluteTime deadline
;
244 clock_absolutetime_interval_to_deadline(_downRepeatTime
, &deadline
);
245 thread_call_func_delayed(_autoRepeat
, this, deadline
);
246 _calloutPending
= true;
250 void IOHIKeyboard::_autoRepeat(thread_call_param_t arg
,
251 thread_call_param_t
) /* thread_call_func_t */
253 IOHIKeyboard
*self
= (IOHIKeyboard
*) arg
;
257 void IOHIKeyboard::autoRepeat()
258 // Description: Repeat the currently pressed key and schedule ourselves
259 // to be called again after another interval elapses.
261 // * Should only be executed on callout thread
262 // * _deviceLock should be unlocked on entry.
264 IOTakeLock( _deviceLock
);
265 if ( _calloutPending
== false )
267 IOUnlock( _deviceLock
);
270 _calloutPending
= false;
273 if ( AbsoluteTime_to_scalar(&_downRepeatTime
) )
275 // Device is due to generate a repeat
276 if (_keyMap
) _keyMap
->translateKeyCode(_codeToRepeat
,
277 /* direction */ true,
278 /* keyBits */ _keyState
);
279 _downRepeatTime
= _keyRepeat
;
283 scheduleAutoRepeat();
284 IOUnlock( _deviceLock
);
287 void IOHIKeyboard::setRepeat(unsigned eventType
, unsigned keyCode
)
288 // Description: Set up or tear down key repeat operations. The method
289 // that locks _deviceLock is a bit higher on the call stack.
290 // This method is invoked as a side effect of our own
291 // invocation of _keyMap->translateKeyCode().
293 // * _deviceLock should be held upon entry.
295 if ( _isRepeat
== false ) // make sure we're not already repeating
297 if (eventType
== NX_KEYDOWN
) // Start repeat
299 // Set this key to repeat (push out last key if present)
300 _downRepeatTime
= _initialKeyRepeat
; // + _lastEventTime;
301 _codeToRepeat
= keyCode
;
302 // reschedule key repeat event here
303 scheduleAutoRepeat();
305 else if (eventType
== NX_KEYUP
) // End repeat
307 /* Remove from downKey */
308 if (_codeToRepeat
== keyCode
)
310 AbsoluteTime_to_scalar(&_downRepeatTime
) = 0;
311 _codeToRepeat
= (unsigned)-1;
312 scheduleAutoRepeat();
319 // BEGIN: Implementation of the methods required by IOHIKeyboardMapper.
322 void IOHIKeyboard::keyboardEvent(unsigned eventType
,
323 /* flags */ unsigned flags
,
324 /* keyCode */ unsigned keyCode
,
325 /* charCode */ unsigned charCode
,
326 /* charSet */ unsigned charSet
,
327 /* originalCharCode */ unsigned origCharCode
,
328 /* originalCharSet */ unsigned origCharSet
)
329 // Description: We use this notification to set up our _keyRepeat timer
330 // and to pass along the event to our owner. This method
331 // will be called while the KeyMap object is processing
332 // the key code we've sent it using deliverKey.
335 if (_keyboardEventAction
) /* upstream call */
337 (*_keyboardEventAction
)(_keyboardEventTarget
,
340 /* keyCode */ keyCode
,
341 /* charCode */ charCode
,
342 /* charSet */ charSet
,
343 /* originalCharCode */ origCharCode
,
344 /* originalCharSet */ origCharSet
,
345 /* keyboardType */ _deviceType
,
346 /* repeat */ _isRepeat
,
347 /* atTime */ _lastEventTime
);
351 if( keyCode
== _keyMap
->getParsedSpecialKey(NX_KEYTYPE_CAPS_LOCK
) ||
352 keyCode
== _keyMap
->getParsedSpecialKey(NX_POWER_KEY
) )
354 //Don't repeat caps lock on ADB/USB. 0x39 is default ADB code.
355 // We are here because KeyCaps needs to see 0x39 as a real key,
356 // not just another modifier bit.
358 if (_interfaceType
== NX_EVS_DEVICE_INTERFACE_ADB
)
364 // Set up key repeat operations here.
365 setRepeat(eventType
, keyCode
);
368 void IOHIKeyboard::keyboardSpecialEvent(unsigned eventType
,
369 /* flags */ unsigned flags
,
370 /* keyCode */ unsigned keyCode
,
371 /* specialty */ unsigned flavor
)
372 // Description: See the description for keyboardEvent.
375 if (_keyboardSpecialEventAction
) /* upstream call */
377 (*_keyboardSpecialEventAction
)(_keyboardSpecialEventTarget
,
380 /* keyCode */ keyCode
,
381 /* specialty */ flavor
,
383 /* repeat */ _isRepeat
,
384 /* atTime */ _lastEventTime
);
387 // Set up key repeat operations here.
389 // Don't repeat caps lock, numlock or power key.
391 if ( (flavor
!= NX_KEYTYPE_CAPS_LOCK
) && (flavor
!= NX_KEYTYPE_NUM_LOCK
) &&
392 (flavor
!= NX_POWER_KEY
) )
394 setRepeat(eventType
, keyCode
);
398 void IOHIKeyboard::updateEventFlags(unsigned flags
)
399 // Description: Process non-event-generating flag changes. Simply pass this
400 // along to our owner.
402 if (_updateEventFlagsAction
) /* upstream call */
404 (*_updateEventFlagsAction
)(_updateEventFlagsTarget
, flags
);
408 unsigned IOHIKeyboard::eventFlags()
409 // Description: Return global event flags In this world, there is only
410 // one keyboard device so device flags == global flags.
415 unsigned IOHIKeyboard::deviceFlags()
416 // Description: Return per-device event flags. In this world, there is only
417 // one keyboard device so device flags == global flags.
422 void IOHIKeyboard::setDeviceFlags(unsigned flags
)
423 // Description: Set device event flags. In this world, there is only
424 // one keyboard device so device flags == global flags.
429 bool IOHIKeyboard::alphaLock()
430 // Description: Return current alpha-lock state. This is a state tracking
431 // callback used by the KeyMap object.
436 void IOHIKeyboard::setAlphaLock(bool val
)
437 // Description: Set current alpha-lock state This is a state tracking
438 // callback used by the KeyMap object.
441 setAlphaLockFeedback(val
);
444 bool IOHIKeyboard::numLock()
449 void IOHIKeyboard::setNumLock(bool val
)
452 setNumLockFeedback(val
);
455 bool IOHIKeyboard::charKeyActive()
456 // Description: Return true If a character generating key down This is a state
457 // tracking callback used by the KeyMap object.
459 return _charKeyActive
;
462 void IOHIKeyboard::setCharKeyActive(bool val
)
463 // Description: Note whether a char generating key is down. This is a state
464 // tracking callback used by the KeyMap object.
466 _charKeyActive
= val
;
469 // END: Implementation of the methods required by IOHIKeyboardMapper.
472 void IOHIKeyboard::dispatchKeyboardEvent(unsigned int keyCode
,
473 /* direction */ bool goingDown
,
474 /* timeStamp */ AbsoluteTime time
)
475 // Description: This method is the heart of event dispatching. The overlying
476 // subclass invokes this method with each event. We then
477 // get the event xlated and dispatched using a _keyMap instance.
478 // The event structure passed in by reference should not be freed.
480 _lastEventTime
= time
;
482 IOTakeLock( _deviceLock
);
484 if (_keyMap
) _keyMap
->translateKeyCode(keyCode
,
485 /* direction */ goingDown
,
486 /* keyBits */ _keyState
);
487 IOUnlock( _deviceLock
);
490 const unsigned char * IOHIKeyboard::defaultKeymapOfLength(UInt32
* length
)
496 void IOHIKeyboard::setAlphaLockFeedback(bool /* val */)
501 void IOHIKeyboard::setNumLockFeedback(bool /* val */)
506 UInt32
IOHIKeyboard::maxKeyCodes()
511 bool IOHIKeyboard:: doesKeyLock ( unsigned key
)
516 unsigned IOHIKeyboard:: getLEDStatus ()
522 bool IOHIKeyboard::open(IOService
* client
,
523 IOOptionBits options
,
524 KeyboardEventAction keAction
,
525 KeyboardSpecialEventAction kseAction
,
526 UpdateEventFlagsAction uefAction
)
528 if ( (!_keyMap
) && (!resetKeyboard())) return false;
530 // IOLog("***open -- gKeyRepeat.lo = %08lx\n", gKeyRepeat.lo );
531 // IOLog("***open -- gInitialKeyRepeat.lo = %08lx\n", gInitialKeyRepeat.lo );
533 if (super::open(client
, options
))
535 // Note: client object is already retained by superclass' open()
536 _keyboardEventTarget
= client
;
537 _keyboardEventAction
= keAction
;
538 _keyboardSpecialEventTarget
= client
;
539 _keyboardSpecialEventAction
= kseAction
;
540 _updateEventFlagsTarget
= client
;
541 _updateEventFlagsAction
= uefAction
;
549 void IOHIKeyboard::close(IOService
* client
, IOOptionBits
)
551 // IOLog("***close -- gKeyRepeat.lo = %08lx\n", gKeyRepeat.lo );
552 // IOLog("***close -- gInitialKeyRepeat.lo = %08lx\n", gInitialKeyRepeat.lo );
554 // Save repeat rate and delay, so when we are replugged we'll be ready
555 // with the right values.
557 gKeyRepeat
= _keyRepeat
;
558 gInitialKeyRepeat
= _initialKeyRepeat
;
560 // kill autorepeat task
561 AbsoluteTime_to_scalar(&_downRepeatTime
) = 0;
562 _codeToRepeat
= (unsigned)-1;
563 scheduleAutoRepeat();
564 // clear modifiers to avoid stuck keys
566 if (_updateEventFlagsAction
)
567 (*_updateEventFlagsAction
)(_updateEventFlagsTarget
, 0); _eventFlags
= 0;
568 bzero(_keyState
, _keyStateSize
);
570 _keyboardEventAction
= NULL
;
571 _keyboardEventTarget
= 0;
572 _keyboardSpecialEventAction
= NULL
;
573 _keyboardSpecialEventTarget
= 0;
574 _updateEventFlagsAction
= NULL
;
575 _updateEventFlagsTarget
= 0;
577 super::close(client
);