PRUint32 KeymapWrapper::GetCharCodeFor(const GdkEventKey *aGdkKeyEvent, guint aModifierState, gint aGroup) { guint keyval; if (!gdk_keymap_translate_keyboard_state(mGdkKeymap, aGdkKeyEvent->hardware_keycode, GdkModifierType(aModifierState), aGroup, &keyval, NULL, NULL, NULL)) { return 0; } GdkEventKey tmpEvent = *aGdkKeyEvent; tmpEvent.state = aModifierState; tmpEvent.keyval = keyval; tmpEvent.group = aGroup; return GetCharCodeFor(&tmpEvent); }
KeyNameIndex KeymapWrapper::ComputeDOMKeyNameIndex(const GdkEventKey* aGdkKeyEvent) { switch (aGdkKeyEvent->keyval) { #define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \ case aNativeKey: return aKeyNameIndex; #include "NativeKeyToDOMKeyName.h" #undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX default: break; } uint32_t ch = GetCharCodeFor(aGdkKeyEvent); return ch ? KEY_NAME_INDEX_PrintableKey : KEY_NAME_INDEX_Unidentified; }
/* static */ PRUint32 KeymapWrapper::ComputeDOMKeyCode(const GdkEventKey* aGdkKeyEvent) { // If the keyval indicates it's a modifier key, we should use unshifted // key's modifier keyval. guint keyval = aGdkKeyEvent->keyval; if (GetModifierForGDKKeyval(keyval)) { // But if the keyval without modifiers isn't a modifier key, we // shouldn't use it. E.g., Japanese keyboard layout's // Shift + Eisu-Toggle key is CapsLock. This is an actual rare case, // Windows uses different keycode for a physical key for different // shift key state. guint keyvalWithoutModifier = GetGDKKeyvalWithoutModifier(aGdkKeyEvent); if (GetModifierForGDKKeyval(keyvalWithoutModifier)) { keyval = keyvalWithoutModifier; } return GetDOMKeyCodeFromKeyPairs(keyval); } // If the key isn't printable, let's look at the key pairs. PRUint32 charCode = GetCharCodeFor(aGdkKeyEvent); if (!charCode) { // Always use unshifted keycode for the non-printable key. // XXX It might be better to decide DOM keycode from all keyvals of // the hardware keycode. However, I think that it's too excessive. guint keyvalWithoutModifier = GetGDKKeyvalWithoutModifier(aGdkKeyEvent); PRUint32 DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyvalWithoutModifier); if (!DOMKeyCode) { // If the unshifted keyval couldn't be mapped to a DOM keycode, // we should fallback to legacy logic, so, we should recompute with // the keyval with aGdkKeyEvent. DOMKeyCode = GetDOMKeyCodeFromKeyPairs(keyval); } return DOMKeyCode; } // printable numpad keys should be resolved here. switch (keyval) { case GDK_KP_Multiply: return NS_VK_MULTIPLY; case GDK_KP_Add: return NS_VK_ADD; case GDK_KP_Separator: return NS_VK_SEPARATOR; case GDK_KP_Subtract: return NS_VK_SUBTRACT; case GDK_KP_Decimal: return NS_VK_DECIMAL; case GDK_KP_Divide: return NS_VK_DIVIDE; case GDK_KP_0: return NS_VK_NUMPAD0; case GDK_KP_1: return NS_VK_NUMPAD1; case GDK_KP_2: return NS_VK_NUMPAD2; case GDK_KP_3: return NS_VK_NUMPAD3; case GDK_KP_4: return NS_VK_NUMPAD4; case GDK_KP_5: return NS_VK_NUMPAD5; case GDK_KP_6: return NS_VK_NUMPAD6; case GDK_KP_7: return NS_VK_NUMPAD7; case GDK_KP_8: return NS_VK_NUMPAD8; case GDK_KP_9: return NS_VK_NUMPAD9; } KeymapWrapper* keymapWrapper = GetInstance(); // Ignore all modifier state except NumLock. guint baseState = (aGdkKeyEvent->state & keymapWrapper->GetModifierMask(NUM_LOCK)); // Basically, we should use unmodified character for deciding our keyCode. PRUint32 unmodifiedChar = keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState, aGdkKeyEvent->group); if (IsBasicLatinLetterOrNumeral(unmodifiedChar)) { // If the unmodified character is an ASCII alphabet or an ASCII // numeric, it's the best hint for deciding our keyCode. return WidgetUtils::ComputeKeyCodeFromChar(unmodifiedChar); } // If the unmodified character is not an ASCII character, that means we // couldn't find the hint. We should reset it. if (unmodifiedChar > 0x7F) { unmodifiedChar = 0; } // Retry with shifted keycode. guint shiftState = (baseState | keymapWrapper->GetModifierMask(SHIFT)); PRUint32 shiftedChar = keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState, aGdkKeyEvent->group); if (IsBasicLatinLetterOrNumeral(shiftedChar)) { // A shifted character can be an ASCII alphabet on Hebrew keyboard // layout. And also shifted character can be an ASCII numeric on // AZERTY keyboad layout. Then, it's a good hint for deciding our // keyCode. return WidgetUtils::ComputeKeyCodeFromChar(shiftedChar); } // If the shifted unmodified character isn't an ASCII character, we should // discard it too. if (shiftedChar > 0x7F) { shiftedChar = 0; } // If current keyboard layout isn't ASCII alphabet inputtable layout, // look for ASCII alphabet inputtable keyboard layout. If the key // inputs an ASCII alphabet or an ASCII numeric, we should use it // for deciding our keyCode. // Note that it's important not to use alternative keyboard layout for ASCII // alphabet inputabble keyboard layout because the keycode for the key with // alternative keyboard layout may conflict with another key on current // keyboard layout. if (!keymapWrapper->IsLatinGroup(aGdkKeyEvent->group)) { gint minGroup = keymapWrapper->GetFirstLatinGroup(); if (minGroup >= 0) { PRUint32 unmodCharLatin = keymapWrapper->GetCharCodeFor(aGdkKeyEvent, baseState, minGroup); if (IsBasicLatinLetterOrNumeral(unmodCharLatin)) { // If the unmodified character is an ASCII alphabet or // an ASCII numeric, we should use it for the keyCode. return WidgetUtils::ComputeKeyCodeFromChar(unmodCharLatin); } PRUint32 shiftedCharLatin = keymapWrapper->GetCharCodeFor(aGdkKeyEvent, shiftState, minGroup); if (IsBasicLatinLetterOrNumeral(shiftedCharLatin)) { // If the shifted character is an ASCII alphabet or an ASCII // numeric, we should use it for the keyCode. return WidgetUtils::ComputeKeyCodeFromChar(shiftedCharLatin); } } } // If unmodified character is in ASCII range, use it. Otherwise, use // shifted character. if (!unmodifiedChar && !shiftedChar) { return 0; } return WidgetUtils::ComputeKeyCodeFromChar( unmodifiedChar ? unmodifiedChar : shiftedChar); }
for (PRUint32 i = 0; i < ArrayLength(kKeyPairs); i++) { if (kKeyPairs[i].GDKKeyval == aGdkKeyval) { return kKeyPairs[i].DOMKeyCode; } } return 0; } void KeymapWrapper::InitKeypressEvent(nsKeyEvent& aKeyEvent, GdkEventKey* aGdkKeyEvent) { NS_ENSURE_TRUE(aKeyEvent.message == NS_KEY_PRESS, ); aKeyEvent.charCode = GetCharCodeFor(aGdkKeyEvent); if (!aKeyEvent.charCode) { PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, ("KeymapWrapper(%p): InitKeypressEvent, " "keyCode=0x%02X, charCode=0x%08X", this, aKeyEvent.keyCode, aKeyEvent.charCode)); return; } // If the event causes inputting a character, keyCode must be zero. aKeyEvent.keyCode = 0; // If Ctrl or Alt or Meta is pressed, we need to append the key details // for handling shortcut key. Otherwise, we have no additional work. if (!aKeyEvent.IsControl() && !aKeyEvent.IsAlt() && !aKeyEvent.IsMeta()) { PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS,
void KeymapWrapper::InitKeypressEvent(nsKeyEvent& aKeyEvent, GdkEventKey* aGdkKeyEvent) { NS_ENSURE_TRUE_VOID(aKeyEvent.message == NS_KEY_PRESS); aKeyEvent.charCode = GetCharCodeFor(aGdkKeyEvent); if (!aKeyEvent.charCode) { PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, ("KeymapWrapper(%p): InitKeypressEvent, " "keyCode=0x%02X, charCode=0x%08X", this, aKeyEvent.keyCode, aKeyEvent.charCode)); return; } // If the event causes inputting a character, keyCode must be zero. aKeyEvent.keyCode = 0; // If Ctrl or Alt or Meta or OS is pressed, we need to append the key // details for handling shortcut key. Otherwise, we have no additional // work. if (!aKeyEvent.IsControl() && !aKeyEvent.IsAlt() && !aKeyEvent.IsMeta() && !aKeyEvent.IsOS()) { PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, ("KeymapWrapper(%p): InitKeypressEvent, " "keyCode=0x%02X, charCode=0x%08X", this, aKeyEvent.keyCode, aKeyEvent.charCode)); return; } gint level = GetKeyLevel(aGdkKeyEvent); if (level != 0 && level != 1) { PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, ("KeymapWrapper(%p): InitKeypressEvent, " "keyCode=0x%02X, charCode=0x%08X, level=%d", this, aKeyEvent.keyCode, aKeyEvent.charCode, level)); return; } guint baseState = aGdkKeyEvent->state & ~(GetModifierMask(SHIFT) | GetModifierMask(CTRL) | GetModifierMask(ALT) | GetModifierMask(META) | GetModifierMask(SUPER) | GetModifierMask(HYPER)); // We shold send both shifted char and unshifted char, all keyboard layout // users can use all keys. Don't change event.charCode. On some keyboard // layouts, Ctrl/Alt/Meta keys are used for inputting some characters. nsAlternativeCharCode altCharCodes(0, 0); // unshifted charcode of current keyboard layout. altCharCodes.mUnshiftedCharCode = GetCharCodeFor(aGdkKeyEvent, baseState, aGdkKeyEvent->group); bool isLatin = (altCharCodes.mUnshiftedCharCode <= 0xFF); // shifted charcode of current keyboard layout. altCharCodes.mShiftedCharCode = GetCharCodeFor(aGdkKeyEvent, baseState | GetModifierMask(SHIFT), aGdkKeyEvent->group); isLatin = isLatin && (altCharCodes.mShiftedCharCode <= 0xFF); if (altCharCodes.mUnshiftedCharCode || altCharCodes.mShiftedCharCode) { aKeyEvent.alternativeCharCodes.AppendElement(altCharCodes); } bool needLatinKeyCodes = !isLatin; if (!needLatinKeyCodes) { needLatinKeyCodes = (IS_ASCII_ALPHABETICAL(altCharCodes.mUnshiftedCharCode) != IS_ASCII_ALPHABETICAL(altCharCodes.mShiftedCharCode)); } // If current keyboard layout can input Latin characters, we don't need // more information. if (!needLatinKeyCodes) { PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, ("KeymapWrapper(%p): InitKeypressEvent, keyCode=0x%02X, " "charCode=0x%08X, level=%d, altCharCodes={ " "mUnshiftedCharCode=0x%08X, mShiftedCharCode=0x%08X }", this, aKeyEvent.keyCode, aKeyEvent.charCode, level, altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode)); return; } // Next, find Latin inputtable keyboard layout. gint minGroup = GetFirstLatinGroup(); if (minGroup < 0) { PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, ("KeymapWrapper(%p): InitKeypressEvent, " "Latin keyboard layout isn't found: " "keyCode=0x%02X, charCode=0x%08X, level=%d, " "altCharCodes={ mUnshiftedCharCode=0x%08X, " "mShiftedCharCode=0x%08X }", this, aKeyEvent.keyCode, aKeyEvent.charCode, level, altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode)); return; } nsAlternativeCharCode altLatinCharCodes(0, 0); uint32_t unmodifiedCh = aKeyEvent.IsShift() ? altCharCodes.mShiftedCharCode : altCharCodes.mUnshiftedCharCode; // unshifted charcode of found keyboard layout. uint32_t ch = GetCharCodeFor(aGdkKeyEvent, baseState, minGroup); altLatinCharCodes.mUnshiftedCharCode = IsBasicLatinLetterOrNumeral(ch) ? ch : 0; // shifted charcode of found keyboard layout. ch = GetCharCodeFor(aGdkKeyEvent, baseState | GetModifierMask(SHIFT), minGroup); altLatinCharCodes.mShiftedCharCode = IsBasicLatinLetterOrNumeral(ch) ? ch : 0; if (altLatinCharCodes.mUnshiftedCharCode || altLatinCharCodes.mShiftedCharCode) { aKeyEvent.alternativeCharCodes.AppendElement(altLatinCharCodes); } // If the charCode is not Latin, and the level is 0 or 1, we should // replace the charCode to Latin char if Alt and Meta keys are not // pressed. (Alt should be sent the localized char for accesskey // like handling of Web Applications.) ch = aKeyEvent.IsShift() ? altLatinCharCodes.mShiftedCharCode : altLatinCharCodes.mUnshiftedCharCode; if (ch && !(aKeyEvent.IsAlt() || aKeyEvent.IsMeta()) && aKeyEvent.charCode == unmodifiedCh) { aKeyEvent.charCode = ch; } PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, ("KeymapWrapper(%p): InitKeypressEvent, " "keyCode=0x%02X, charCode=0x%08X, level=%d, minGroup=%d, " "altCharCodes={ mUnshiftedCharCode=0x%08X, " "mShiftedCharCode=0x%08X } " "altLatinCharCodes={ mUnshiftedCharCode=0x%08X, " "mShiftedCharCode=0x%08X }", this, aKeyEvent.keyCode, aKeyEvent.charCode, level, minGroup, altCharCodes.mUnshiftedCharCode, altCharCodes.mShiftedCharCode, altLatinCharCodes.mUnshiftedCharCode, altLatinCharCodes.mShiftedCharCode)); }