Пример #1
0
/* Send power messages to rootDomain */
bool Insomnia::send_event(UInt32 msg) {
	IOPMrootDomain *root = NULL;
	IOReturn		ret=kIOReturnSuccess;
	char			err_str[100];
	
	IOLog("Insomina: Sending event\n");
	
	root = getPMRootDomain();
	if (!root) {
		IOLog("Insomnia: Fatal error could not get RootDomain.\n");
		return false;
	}
	
	
	ret = root->receivePowerNotification(msg);
	
	IOLog("Insomnia: root returns %d\n", ret);
	
	if(ret!=kIOReturnSuccess)
	{
		snprintf(err_str, 100, "Insomina: Error sending event: %d\n", ret);
		IOLog("%s", err_str);
	}
	else
		IOLog("Insomnia: Message sent to root\n");
	
	return true;
}
Пример #2
0
/* Send power messages to rootDomain */
bool Insomnia::send_event(UInt32 msg) {
    IOPMrootDomain *root = NULL;
    IOReturn        ret=kIOReturnSuccess;
    
    DLog("");
    
    root = getPMRootDomain();
    if (!root) {
        DLog("Fatal error could not get RootDomain.");
        return false;
    }

    ret = root->receivePowerNotification(msg);
    
    Log("root returns %d", ret);
    
    if(ret!=kIOReturnSuccess)
    {
        DLog("Error sending event: %d", ret);
    }
    else
        Log("Message sent to root");
    
    return true;
}
bool ApplePS2Keyboard::dispatchKeyboardEventWithScancode(UInt8 scanCode)
{
  //
  // Parses the given scan code, updating all necessary internal state, and
  // should a new key be detected, the key event is dispatched.
  //
  // Returns true if a key event was indeed dispatched.
  //

  unsigned int keyCode;
  bool         goingDown;
  AbsoluteTime now;

  //
  // See if this scan code introduces an extended key sequence.  If so, note
  // it and then return.  Next time we get a key we'll finish the sequence.
  //

  if (scanCode == kSC_Extend)
  {
    _extendCount = 1;
    return false;
  }

  //
  // See if this scan code introduces an extended key sequence for the Pause
  // Key.  If so, note it and then return.  The next time we get a key, drop
  // it.  The next key we get after that finishes the Pause Key sequence.
  //
  // The sequence actually sent to us by the keyboard for the Pause Key is:
  //
  // 1. E1  Extended Sequence for Pause Key
  // 2. 1D  Useless Data, with Up Bit Cleared
  // 3. 45  Pause Key, with Up Bit Cleared
  // 4. E1  Extended Sequence for Pause Key
  // 5. 9D  Useless Data, with Up Bit Set
  // 6. C5  Pause Key, with Up Bit Set
  //
  // The reason items 4 through 6 are sent with the Pause Key is because the
  // keyboard hardware never generates a release code for the Pause Key and
  // the designers are being smart about it.  The sequence above translates
  // to this parser as two separate events, as it should be -- one down key
  // event and one up key event (for the Pause Key).
  //

  if (scanCode == kSC_Pause)
  {
    _extendCount = 2;
    return false;
  }

  //
  // Convert the scan code into a key code.
  //

	//IOLog("key 0x%x scan 0x%x ex %d\n",(scanCode & ~kSC_UpBit),scanCode,_extendCount);

  if (_extendCount == 0)
  {
    keyCode = scanCode & ~kSC_UpBit;

    // from "The Undocumented PC" chapter 8, The Keyboard System some
    // keyboard scan codes are single byte, some are multi-byte
    // 3023805:  I want to swap alt and windows, since the windows
    // key is located where the alt/option key is on an Apple PowerBook
    // or USB keyboard, and the alt key is where the Apple/Command
    // key is on the PB or USB keyboard. Left alt is a single scan
    // code byte, right alt is a double scan code byte. Left and
    // right windows keys are double bytes.  This is all set by an
    // entry in Info.plist for ApplePS2Keyboard.kext
    switch (keyCode)
    {
      case 0x3A: 
	if (emacsMode == true) {
	  keyCode = 0x60; 
	}
	break;			// caps lock becomes ctrl
      case 0x38: 
	if (macintoshMode == true) {
	  keyCode = 0x70; 
	}
	break;		// left alt becomes left windows
/* CFR: Nope...this is the code for =+
		case 0xd: // ²		
		if(scanCode==0xd) 
		{
			_extendCount=1; dispatchKeyboardEventWithScancode(0x5b);
			dispatchKeyboardEventWithScancode(0x56);
		}
		else
		{
			_extendCount=1; dispatchKeyboardEventWithScancode(0xdb);
			dispatchKeyboardEventWithScancode(0xd6);
		}
		return true;
*/
// CFR		case 0x56: keyCode = 0x29; break;            // <
// CFR		case 0x1a: keyCode = 0xd; break;            // +
// CFR		case 0x28: keyCode = 0x1a; break;            // ¼ »
// CFR		case 0x2b: keyCode = 0x28; break;            // ~
// CFR		case 0x29: keyCode = 0x2b; break;            
		case 0x8:
		if (keyi==true)	
		{
			if(scanCode==0x8) 
			{
				dispatchKeyboardEventWithScancode(0x2a);
			}
			else
			{
				dispatchKeyboardEventWithScancode(0xaa);
			}
			keyCode = 0x9;
		}
		break;
		case 0xb: 
		if (keyi==true)	
		{
			if(scanCode==0xb) 
			{
				dispatchKeyboardEventWithScancode(0x2a);
			}
			else
			{
				dispatchKeyboardEventWithScancode(0xaa);
			}
			keyCode = 0xa;
		}
		break;
		case 0x12: 
		if (keyi==true)	keyCode = 0x4;
		break;
		case 0x4: 
		if (keyi==true)	keyCode = 0x5;
		break; 
		case 0x5:
		if (keyi==true)	keyCode = 0xc;
		break;

    }
  }
  else
  {
    _extendCount--;
    if (_extendCount)  return false;

    //
    // Convert certain extended codes on the PC keyboard into single scancodes.
    // Refer to the conversion table in defaultKeymapOfLength.
    //

    switch (scanCode & ~kSC_UpBit)
    {	  	  

	  case 0x33: // Û
	  if(scanCode==0x33) 
		{
			dispatchKeyboardEventWithScancode(0x38);
			dispatchKeyboardEventWithScancode(0x10);
		}
		else
		{
			dispatchKeyboardEventWithScancode(0xb8);
			dispatchKeyboardEventWithScancode(0x90);
		}
		return true;
	  case 0x34: // $ = F12 - press and hold to eject cd rom
	  if (scanCode==0x34) 
	  {
		dispatchKeyboardEventWithScancode(0x58); 
		//dispatchKeyboardEventWithScancode(0x58); 
	  }
	  else 
	  {
		dispatchKeyboardEventWithScancode(0xd8); 
		//dispatchKeyboardEventWithScancode(0x58); 
	  }
	  return true;

	   
		 // scancodes from running showkey -s (under Linux) for extra keys on keyboard
      case 0x30: keyCode = 0x7d; break;		   // E030 = volume up
      case 0x2e: keyCode = 0x7e; break;		   // E02E = volume down
      case 0x20: keyCode = 0x7f; break;		   // E020 = volume mute

      case 0x5e: keyCode = 0x7c; break;            // E05E = power
      case 0x5f:                                   // E05F = sleep
        keyCode = 0;
        if (!(scanCode & kSC_UpBit))
        {
          IOPMrootDomain * rootDomain = getPMRootDomain();
          if (rootDomain)
            rootDomain->receivePowerNotification( kIOPMSleepNow );
        }
        break;

      case 0x1D: keyCode = 0x60; break;            // ctrl
      case 0x38:             			   // right alt may become right command
	if (macintoshMode == true) {
	  keyCode = 0x71; 
	} else {
	  keyCode = 0x61;			  
	}
	break;

      case 0x1C: keyCode = 0x62; break;            // enter
      case 0x35: keyCode = 0x63; break;            // /
      case 0x48: keyCode = 0x64; break;            // up arrow
      case 0x50: keyCode = 0x65; break;            // down arrow
      case 0x4B: keyCode = 0x66; break;            // left arrow
      case 0x4D: keyCode = 0x67; break;            // right arrow
      case 0x52: keyCode = 0x68; break;            // insert 0x68
      case 0x53: keyCode = 0x69; break;            // delete
      case 0x49: keyCode = 0x6A; break;            // page up
      case 0x51: keyCode = 0x6B; break;            // page down
      case 0x47: keyCode = 0x6C; break;            // home
      case 0x4F: keyCode = 0x6D; break;            // end
      case 0x37: //keyCode = 0x6E; break;            // PrintScreen
	  if(scanCode==0x37) 
		{
			dispatchKeyboardEventWithScancode(0x1d);
			dispatchKeyboardEventWithScancode(0x38);
			dispatchKeyboardEventWithScancode(0x2a);
			dispatchKeyboardEventWithScancode(0x5); 
		}
		else
		{
			dispatchKeyboardEventWithScancode(0x9d);
			dispatchKeyboardEventWithScancode(0xb8);
			dispatchKeyboardEventWithScancode(0xaa);
			dispatchKeyboardEventWithScancode(0x85); 
		}
		return true;
      case 0x45: //keyCode = 0x6F; break;            // Pause
       if(scanCode==0x45) 
		{
			dispatchKeyboardEventWithScancode(0x1d);
			dispatchKeyboardEventWithScancode(0x2e);
		}
		else
		{
			dispatchKeyboardEventWithScancode(0x9d);
			dispatchKeyboardEventWithScancode(0xae);
		}
		return true;
	  case 0x5B: 				   // left Windows key may become alt
	if (macintoshMode == true) {
	  keyCode = 0x38; 
	   if (scanCode==0x5B) keyi=true; else keyi=false;			   // alt 
	} else {
	  keyCode = 0x70;			   // Left command
	}
	break;
      case 0x5c:  				   // right Windows key may become alt
	if (macintoshMode == true) {
	  keyCode = 0x61; 			   // alt
	} else {
	  keyCode = 0x71; 			   // Right command
	}
	break;
      case 0x5D: keyCode = 0x38; if (scanCode==0x5D) keyi=true; else keyi=false; break;            // Application 0x72
      case 0x2A:             // header or trailer for PrintScreen
      default: return false;
    }
  }

	//IOLog("keycode 0x%x\n",keyCode);


  if (keyCode == 0)  return false;

  //
  // Update our key bit vector, which maintains the up/down status of all keys.
  //

  goingDown = !(scanCode & kSC_UpBit);

  if (goingDown)
  {
    //
    // Verify that this is not an autorepeated key -- discard it if it is.
    //

    if (KBV_IS_KEYDOWN(keyCode, _keyBitVector))  return false;

    KBV_KEYDOWN(keyCode, _keyBitVector);
  }
  else
  {
    KBV_KEYUP(keyCode, _keyBitVector);
  }

  //
  // We have a valid key event -- dispatch it to our superclass.
  //

  clock_get_uptime((uint64_t *)&now);

  dispatchKeyboardEvent( PS2ToADBMap[keyCode],
           /*direction*/ goingDown,
           /*timeStamp*/ now );

  return true;
}
bool ApplePS2Keyboard::dispatchKeyboardEventWithScancode(UInt8 scanCode)
{
  //
  // Parses the given scan code, updating all necessary internal state, and
  // should a new key be detected, the key event is dispatched.
  //
  // Returns true if a key event was indeed dispatched.
  //

  unsigned int keyCode;
  bool         goingDown;
  AbsoluteTime now;

    //
    //Accidental Input Keys
    //
    switch (scanCode & ~kSC_UpBit)
    {
        case 0X01://ESC
        case 0X0f://Tab
        case 0x3a://CapsLock
        case 0x2a://Shift
        case 0x36://
        case 0x1d://Cntrl
        case 0x5b://Window
        case 0x38://Alt
        case 0x5d://ContextMenu
        case 0x45://NumLock
        case 0x1c://Enter
        case 0x0e://Backspace
        case 0x64://Arrows
        case 0x65://
        case 0x66://
        case 0x67://
            _accidentalInputKeysException = true;
            break;
        case 0x52:/* 0........9 */
        case 0x4f:
        case 0x50:
        case 0x51:
        case 0x4b:
        case 0x4c:
        case 0x4d:
        case 0x47:
        case 0x48:
        case 0x49:
        case 0x53:/* ". / * - + ENTER" */
        case 0x63:
        case 0x37:
        case 0x4a:
        case 0x4e:
        case 0x62:
            _keyPadKeys = true;
            break;
        default:
            break;
    }

  //
  // See if this scan code introduces an extended key sequence.  If so, note
  // it and then return.  Next time we get a key we'll finish the sequence.
  //

  if (scanCode == kSC_Extend)
  {
    _extendCount = 1;
    return false;
  }

  //
  // See if this scan code introduces an extended key sequence for the Pause
  // Key.  If so, note it and then return.  The next time we get a key, drop
  // it.  The next key we get after that finishes the Pause Key sequence.
  //
  // The sequence actually sent to us by the keyboard for the Pause Key is:
  //
  // 1. E1  Extended Sequence for Pause Key
  // 2. 1D  Useless Data, with Up Bit Cleared
  // 3. 45  Pause Key, with Up Bit Cleared
  // 4. E1  Extended Sequence for Pause Key
  // 5. 9D  Useless Data, with Up Bit Set
  // 6. C5  Pause Key, with Up Bit Set
  //
  // The reason items 4 through 6 are sent with the Pause Key is because the
  // keyboard hardware never generates a release code for the Pause Key and
  // the designers are being smart about it.  The sequence above translates
  // to this parser as two separate events, as it should be -- one down key
  // event and one up key event (for the Pause Key).
  //

  if (scanCode == kSC_Pause)
  {
    _extendCount = 2;
    return false;
  }

  //
  // Convert the scan code into a key code.
  //

  if (_extendCount == 0)
  {
    keyCode = scanCode & ~kSC_UpBit;

    // from "The Undocumented PC" chapter 8, The Keyboard System some
    // keyboard scan codes are single byte, some are multi-byte
    // 3023805:  I want to swap alt and windows, since the windows
    // key is located where the alt/option key is on an Apple PowerBook
    // or USB keyboard, and the alt key is where the Apple/Command
    // key is on the PB or USB keyboard. Left alt is a single scan
    // code byte, right alt is a double scan code byte. Left and
    // right windows keys are double bytes.  This is all set by an
    // entry in Info.plist for ApplePS2Keyboard.kext
    switch (keyCode)
    {
      case 0x3A: 
	if (emacsMode == true) {
	  keyCode = 0x60; 
	}
	break;			// caps lock becomes ctrl
      case 0x38: 
	if (macintoshMode == true) {
	  keyCode = 0x70; 
	}
	break;		// left alt becomes left windows
    }
  }
  else
  {
    _extendCount--;
    if (_extendCount)  return false;
      
      
    //
    // Convert certain extended codes on the PC keyboard into single scancodes.
    // Refer to the conversion table in defaultKeymapOfLength.
    //

    switch (scanCode & ~kSC_UpBit)
    {
      // scancodes from running showkey -s (under Linux) for extra keys on keyboard
      case 0x30: keyCode = 0x7d; break;		   // E030 = volume up
      case 0x2e: keyCode = 0x7e; break;		   // E02E = volume down
      case 0x20: keyCode = 0x7f; break;		   // E020 = volume mute

      case 0x5e: keyCode = 0x7c; break;            // E05E = power
      case 0x5f:                                   // E05F = sleep
        keyCode = 0;
        if (!(scanCode & kSC_UpBit))
        {
          IOPMrootDomain * rootDomain = getPMRootDomain();
          if (rootDomain)
            rootDomain->receivePowerNotification( kIOPMSleepNow );
        }
        break;

      case 0x1D: keyCode = 0x60; break;            // ctrl
      case 0x38:             			   // right alt may become right command
	if (macintoshMode == true) {
	  keyCode = 0x71; 
	} else {
	  keyCode = 0x61;			  
	}
	break;
      case 0x1C: keyCode = 0x62; break;            // enter
      case 0x35: keyCode = 0x63; break;            // /
      case 0x48: keyCode = 0x64; break;            // up arrow
      case 0x50: keyCode = 0x65; break;            // down arrow
      case 0x4B: keyCode = 0x66; break;            // left arrow
      case 0x4D: keyCode = 0x67; break;            // right arrow
      case 0x52: keyCode = 0x68; break;            // insert
      case 0x53: keyCode = 0x69; break;            // delete
      case 0x49: keyCode = 0x6A; break;            // page up
      case 0x51: keyCode = 0x6B; break;            // page down
      case 0x47: keyCode = 0x6C; break;            // home
      case 0x4F: keyCode = 0x6D; break;            // end
      case 0x37: keyCode = 0x6E; break;            // PrintScreen
      case 0x45: keyCode = 0x6F; break;            // Pause
      case 0x5B: 				   // left Windows key may become alt
	if (macintoshMode == true) {
	  keyCode = 0x38; 			   // alt 
	} else {
	  keyCode = 0x70;			   // Left command
	}
	break;
      case 0x5d:  				   //right context click key becomes alt (right Windows key may become alt)
	if (macintoshMode == true) {
	  keyCode = 0x61; 			   // alt
	} else {
	  keyCode = 0x71; 			   // Right command
	}
	break;
      //case 0x5D: keyCode = 0x72; break;            // Application
      case 0x2A:             // header or trailer for PrintScreen
      default: return false;
    }
  }

  if (keyCode == 0)  return false;

  //
  // Update our key bit vector, which maintains the up/down status of all keys.
  //

  goingDown = !(scanCode & kSC_UpBit);

  if (goingDown)
  {
    //
    // Verify that this is not an autorepeated key -- discard it if it is.
    //

    if (KBV_IS_KEYDOWN(keyCode, _keyBitVector))  return false;

    KBV_KEYDOWN(keyCode, _keyBitVector);
  }
  else
  {
    KBV_KEYUP(keyCode, _keyBitVector);
  }

  //
  // We have a valid key event -- dispatch it to our superclass.
  //
    
  //IOLog("Keyboard key Code %x %d\n",keyCode,keyCode);
  //Sending PS2 Notification to Mouse/Touchpad
    if(goingDown)
    if(!_accidentalInputKeysException && !_keyPadKeys)
        _device->dispatchPS2Notification(kPS2C_DisableTouchpad);
    
  clock_get_uptime((uint64_t *)&now);

    //NUM LOCK and Print Screen Fix
    if(keyCode == 0x45 && goingDown)
    {
        setNumLockFeedback(_numKeypadLocked);
        _numKeypadLocked = !_numKeypadLocked;

    }
    else if(keyCode == 0x6e && goingDown)//Print Screen Simulation
    {
        dispatchKeyboardEvent( 55,
                              /*direction*/ true,
                              /*timeStamp*/ now );
        clock_get_uptime((uint64_t *)&now);
        dispatchKeyboardEvent( 56,
                              /*direction*/ true,
                              /*timeStamp*/ now );
        clock_get_uptime((uint64_t *)&now);
        dispatchKeyboardEvent( 21,
                              /*direction*/ true,
                              /*timeStamp*/ now );
        clock_get_uptime((uint64_t *)&now);
        dispatchKeyboardEvent( 21,
                              /*direction*/ false,
                              /*timeStamp*/ now );
        clock_get_uptime((uint64_t *)&now);
        dispatchKeyboardEvent( 56,
                              /*direction*/ false,
                              /*timeStamp*/ now );
        clock_get_uptime((uint64_t *)&now);
        dispatchKeyboardEvent( 55,
                              /*direction*/ false,
                              /*timeStamp*/ now );
    }
    else if(!((keyCode == 0x45 || keyCode == 0x6e) ||//NumLock & PrintScreen
            //Keypad Buttons
            ((keyCode == 0x52 || keyCode == 0x53 || keyCode == 0x62 || keyCode == 0x4f || keyCode == 0x50 ||
            keyCode == 0x51 || keyCode == 0x4b || keyCode == 0x4c || keyCode == 0x4d || keyCode == 0x47 ||
            keyCode == 0x48 || keyCode == 0x49 || keyCode == 0x63 || keyCode == 0x37 || keyCode == 0x4a ||
            keyCode == 0x4e)  && _numKeypadLocked)))
        dispatchKeyboardEvent( PS2ToADBMap[keyCode],  //Dispatch of Keyboard Events
           /*direction*/ goingDown,
           /*timeStamp*/ now );

   
    
    //PS2 Notification
    if(!goingDown && !_accidentalInputKeysException && !_keyPadKeys)
        _device->dispatchPS2Notification(kPS2C_EnableTouchpad);
    
    if(_accidentalInputKeysException)
        _accidentalInputKeysException = false;
    if(_keyPadKeys)
        _keyPadKeys = false;

        /*if(keyCode != 0x2a && keyCode != 0x36 && keyCode != 0x1d && keyCode != 0x60 &&
           keyCode != 0x70 && keyCode != 0x71 && keyCode != 0x38 && keyCode != 0x61 &&
           keyCode != 0x72 && keyCode != 0x0f && keyCode != 0x45 && keyCode != 0x6e && !(keyCode>0x3f && keyCode<0x44))*/
    
  return true;
}
bool ApplePS2Keyboard::dispatchKeyboardEventWithScancode(UInt8 scanCode)
{
    // Parses the given scan code, updating all necessary internal state, and
    // should a new key be detected, the key event is dispatched.
    //
    // Returns true if a key event was indeed dispatched.

    DEBUG_LOG("%s: PS/2 scancode 0x%x\n", getName(), scanCode);

    //
    // See if this scan code introduces an extended key sequence.  If so, note
    // it and then return.  Next time we get a key we'll finish the sequence.
    //

    if (scanCode == kSC_Extend)
    {
        _extendCount = 1;
        return false;
    }

    //
    // See if this scan code introduces an extended key sequence for the Pause
    // Key.  If so, note it and then return.  The next time we get a key, drop
    // it.  The next key we get after that finishes the Pause Key sequence.
    //
    // The sequence actually sent to us by the keyboard for the Pause Key is:
    //
    // 1. E1  Extended Sequence for Pause Key
    // 2. 1D  Useless Data, with Up Bit Cleared
    // 3. 45  Pause Key, with Up Bit Cleared
    // 4. E1  Extended Sequence for Pause Key
    // 5. 9D  Useless Data, with Up Bit Set
    // 6. C5  Pause Key, with Up Bit Set
    //
    // The reason items 4 through 6 are sent with the Pause Key is because the
    // keyboard hardware never generates a release code for the Pause Key and
    // the designers are being smart about it.  The sequence above translates
    // to this parser as two separate events, as it should be -- one down key
    // event and one up key event (for the Pause Key).
    //
    if (scanCode == kSC_Pause)
    {
        _extendCount = 2;
        return false;
    }

    unsigned keyCodeRaw = scanCode & ~kSC_UpBit;
    unsigned keyCode;
    uint64_t now;
    clock_get_uptime(&now);

    //
    // Convert the scan code into a key code index.
    //
    // From "The Undocumented PC" chapter 8, The Keyboard System some
    // keyboard scan codes are single byte, some are multi-byte.
    // Scancodes from running showkey -s (under Linux) for extra keys on keyboard
    // Refer to the conversion table in defaultKeymapOfLength 
    // and the conversion table in ApplePS2ToADBMap.h.
    //
    if (_extendCount == 0)
    {
        // LANG1(Hangul) and LANG2(Hanja) make one event only when the key was pressed.
        // Make key-down and key-up event ADB event
        if (scanCode == 0xf2 || scanCode == 0xf1)
        {
            clock_get_uptime(&now);
            dispatchKeyboardEvent( PS2ToADBMap[scanCode], true, *((AbsoluteTime*)&now) );
            clock_get_uptime(&now);
            dispatchKeyboardEvent( PS2ToADBMap[scanCode], false, *((AbsoluteTime*)&now) );
            return true;
        }
        
        // Allow PS2 -> PS2 map to work, look in normal part of the table
        keyCode = _PS2ToPS2Map[keyCodeRaw];
        
#ifdef DEBUG_MSG
        if (keyCode != keyCodeRaw)
            DEBUG_LOG("%s: keycode translated from=0x%02x to=0x%04x\n", getName(), keyCodeRaw, keyCode);
#endif
    }
    else
    {
        // ignore incoming scan codes until extend count is zero
        if (--_extendCount)
            return false;
        
        // allow PS2 -> PS2 map to work, look in extended part of the table
        keyCodeRaw += KBV_NUM_SCANCODES;
        keyCode = _PS2ToPS2Map[keyCodeRaw];
#ifdef DEBUG_MSG
        if (keyCode != keyCodeRaw)
            DEBUG_LOG("%s: keycode translated from=0xe0%02x to=0x%04x\n", getName(), keyCodeRaw, keyCode);
#endif
        // handle special cases
        switch (keyCodeRaw)
        {
            case 0x012a: // header or trailer for PrintScreen
                return false;
        }
    }

    // handle special cases
    switch (keyCode)
    {
        case 0x0153:    // delete
            // check for Ctrl+Alt+Delete? (three finger salute)
            if (KBV_IS_KEYDOWN(0x1d, _keyBitVector) && KBV_IS_KEYDOWN(0x38, _keyBitVector))
            {
                keyCode = 0;
                if (scanCode & kSC_UpBit)
                {
                    // Note: If OS X thinks the Command and Control keys are down at the time of
                    //  receiving an ADB 0x7f (power button), it will unconditionaly and unsafely
                    //  reboot the computer, much like the old PC/AT Ctrl+Alt+Delete!
                    // That's why we make sure Control (0x3b) and Alt (0x37) are up!!
                    dispatchKeyboardEvent(0x37, false, now);
                    dispatchKeyboardEvent(0x3b, false, now);
                    dispatchKeyboardEvent(0x7f, true, now);
                    dispatchKeyboardEvent(0x7f, false, now);
                }
            }
            break;
                
        case 0x015f:    // sleep
            // This code relies on the keyboard sending repeats...  If not, it won't
            // invoke sleep until after time has expired and we get the keyup!
            keyCode = 0;
            if (!KBV_IS_KEYDOWN(keyCodeRaw, _keyBitVector))
                sleeppressedtime = now;
            if (now-sleeppressedtime >= maxsleeppresstime)
            {
                IOPMrootDomain* rootDomain = getPMRootDomain();
                if (NULL != rootDomain)
                    rootDomain->receivePowerNotification(kIOPMSleepNow);
            }
            break;
            
        case 0x0137:    // trackpad on/off
            keyCode = 0;
            if (!(scanCode & kSC_UpBit))
            {
                // get current enabled status, and toggle it
                bool enabled;
                _device->dispatchMouseMessage(kPS2M_getDisableTouchpad, &enabled);
                enabled = !enabled;
                _device->dispatchMouseMessage(kPS2M_setDisableTouchpad, &enabled);
            }
            break;
    }
        
    // Update our key bit vector, which maintains the up/down status of all keys.
    bool goingDown = !(scanCode & kSC_UpBit);
    if (goingDown)
    {
        // discard if auto-repeated key
        if (KBV_IS_KEYDOWN(keyCodeRaw, _keyBitVector))
            return false;

        KBV_KEYDOWN(keyCodeRaw, _keyBitVector);
    }
    else
    {
        KBV_KEYUP(keyCodeRaw, _keyBitVector);
    }

#ifdef DEBUG
    // allow hold Alt+numpad keys to type in arbitrary ADB key code
    static int genADB = -1;
    if (KBV_IS_KEYDOWN(0x38, _keyBitVector) && keyCodeRaw >= 0x47 && keyCodeRaw <= 0x52)
    {
        if (!KBV_IS_KEYDOWN(keyCodeRaw, _keyBitVector))
        {
            // map numpad scan codes to digits
            static int map[0x52-0x47+1] = { 7, 8, 9, -1, 4, 5, 6, -1, 1, 2, 3, 0 };
            if (-1 == genADB)
                genADB = 0;
            int digit = map[keyCodeRaw-0x47];
            if (-1 != digit)
                genADB = genADB * 10 + digit;
            DEBUG_LOG("%s: genADB = %d\n", getName(), genADB);
        }
        keyCode = 0;    // eat it
    }
#endif
    
    // We have a valid key event -- dispatch it to our superclass.
    
    // map scan code to Apple code
    UInt8 adbKeyCode = _PS2ToADBMap[keyCode];
    
#ifdef DEBUG_MSG
    if (adbKeyCode == DEADKEY && 0 != keyCode)
        IOLog("%s: Unknown ADB key for PS2 scancode: 0x%x\n", getName(), scanCode);
    else
        IOLog("%s: ADB key code 0x%x %s\n", getName(), adbKeyCode, goingDown?"down":"up");
#endif
    
    // allow mouse/trackpad driver to have time of last keyboard activity
    // used to implement "PalmNoAction When Typing" and "OutsizeZoneNoAction When Typing"
    PS2KeyInfo info;
    info.time = now;
    info.adbKeyCode = adbKeyCode;
    info.goingDown = goingDown;
    _device->dispatchMouseMessage(kPS2M_notifyKeyPressed, &info);

    // dispatch to HID system
    dispatchKeyboardEvent(adbKeyCode, goingDown, now);
    
#ifdef DEBUG
    if (0x38 == keyCode && !goingDown && -1 != genADB) // Alt going up
    {
        // dispatch typed adb code
        dispatchKeyboardEvent(genADB, true, now);
        dispatchKeyboardEvent(genADB, false, now);
        DEBUG_LOG("%s: sending typed ADB code 0x%x\n", getName(), genADB);
        genADB = -1;
    }
#endif

    return true;
}