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. // 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. 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; }