/* static */ void KeymapWrapper::InitKeyEvent(nsKeyEvent& aKeyEvent, GdkEventKey* aGdkKeyEvent) { KeymapWrapper* keymapWrapper = GetInstance(); aKeyEvent.keyCode = ComputeDOMKeyCode(aGdkKeyEvent); // NOTE: The state of given key event indicates adjacent state of // modifier keys. E.g., even if the event is Shift key press event, // the bit for Shift is still false. By the same token, even if the // event is Shift key release event, the bit for Shift is still true. // Unfortunately, gdk_keyboard_get_modifiers() returns current modifier // state. It means if there're some pending modifier key press or // key release events, the result isn't what we want. // Temporarily, we should compute the state only when the key event // is GDK_KEY_PRESS. // XXX If we could know the modifier keys state at the key release event, // we should cut out changingMask from modifierState. guint modifierState = aGdkKeyEvent->state; if (aGdkKeyEvent->is_modifier && aGdkKeyEvent->type == GDK_KEY_PRESS) { ModifierKey* modifierKey = keymapWrapper->GetModifierKey(aGdkKeyEvent->hardware_keycode); if (modifierKey) { // If new modifier key is pressed, add the pressed mod mask. modifierState |= modifierKey->mMask; } } InitInputEvent(aKeyEvent, modifierState); PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, ("KeymapWrapper(%p): InitKeyEvent, modifierState=0x%08X " "aGdkKeyEvent={ type=%s, keyval=%s(0x%X), state=0x%08X, " "hardware_keycode=0x%08X, is_modifier=%s } " "aKeyEvent={ message=%s, isShift=%s, isControl=%s, " "isAlt=%s, isMeta=%s }", keymapWrapper, modifierState, ((aGdkKeyEvent->type == GDK_KEY_PRESS) ? "GDK_KEY_PRESS" : "GDK_KEY_RELEASE"), gdk_keyval_name(aGdkKeyEvent->keyval), aGdkKeyEvent->keyval, aGdkKeyEvent->state, aGdkKeyEvent->hardware_keycode, GetBoolName(aGdkKeyEvent->is_modifier), ((aKeyEvent.message == NS_KEY_DOWN) ? "NS_KEY_DOWN" : (aKeyEvent.message == NS_KEY_PRESS) ? "NS_KEY_PRESS" : "NS_KEY_UP"), GetBoolName(aKeyEvent.isShift), GetBoolName(aKeyEvent.isControl), GetBoolName(aKeyEvent.isAlt), GetBoolName(aKeyEvent.isMeta))); if (aKeyEvent.message == NS_KEY_PRESS) { keymapWrapper->InitKeypressEvent(aKeyEvent, aGdkKeyEvent); } // The transformations above and in gdk for the keyval are not invertible // so link to the GdkEvent (which will vanish soon after return from the // event callback) to give plugins access to hardware_keycode and state. // (An XEvent would be nice but the GdkEvent is good enough.) aKeyEvent.pluginEvent = (void *)aGdkKeyEvent; aKeyEvent.time = aGdkKeyEvent->time; }
/* static */ guint KeymapWrapper::GetGDKKeyvalWithoutModifier(const GdkEventKey *aGdkKeyEvent) { KeymapWrapper* keymapWrapper = GetInstance(); guint state = (aGdkKeyEvent->state & keymapWrapper->GetModifierMask(NUM_LOCK)); guint keyval; if (!gdk_keymap_translate_keyboard_state(keymapWrapper->mGdkKeymap, aGdkKeyEvent->hardware_keycode, GdkModifierType(state), aGdkKeyEvent->group, &keyval, NULL, NULL, NULL)) { return 0; } return keyval; }
/* static */ bool KeymapWrapper::AreModifiersActive(Modifiers aModifiers, guint aModifierState) { NS_ENSURE_TRUE(aModifiers, false); KeymapWrapper* keymapWrapper = GetInstance(); for (PRUint32 i = 0; i < sizeof(Modifier) * 8 && aModifiers; i++) { Modifier modifier = static_cast<Modifier>(1 << i); if (!(aModifiers & modifier)) { continue; } if (!(aModifierState & keymapWrapper->GetModifierMask(modifier))) { return false; } aModifiers &= ~modifier; } return true; }
/* static */ void KeymapWrapper::InitInputEvent(nsInputEvent& aInputEvent, guint aModifierState) { KeymapWrapper* keymapWrapper = GetInstance(); aInputEvent.isShift = keymapWrapper->AreModifiersActive(SHIFT, aModifierState); aInputEvent.isControl = keymapWrapper->AreModifiersActive(CTRL, aModifierState); aInputEvent.isAlt = keymapWrapper->AreModifiersActive(ALT, aModifierState); // XXX DOM Meta key should be TRUE only on Mac. We need to discuss this // issue later. aInputEvent.isMeta = false; PR_LOG(gKeymapWrapperLog, PR_LOG_DEBUG, ("KeymapWrapper(%p): InitInputEvent, aModifierState=0x%08X " "aKeyEvent={ isShift=%s, isControl=%s, isAlt=%s, isMeta=%s }", keymapWrapper, aModifierState, GetBoolName(aInputEvent.isShift), GetBoolName(aInputEvent.isControl), GetBoolName(aInputEvent.isAlt), GetBoolName(aInputEvent.isMeta))); }
/* static */ void KeymapWrapper::InitKeyEvent(nsKeyEvent& aKeyEvent, GdkEventKey* aGdkKeyEvent) { KeymapWrapper* keymapWrapper = GetInstance(); aKeyEvent.keyCode = ComputeDOMKeyCode(aGdkKeyEvent); // NOTE: The state of given key event indicates adjacent state of // modifier keys. E.g., even if the event is Shift key press event, // the bit for Shift is still false. By the same token, even if the // event is Shift key release event, the bit for Shift is still true. // Unfortunately, gdk_keyboard_get_modifiers() returns current modifier // state. It means if there're some pending modifier key press or // key release events, the result isn't what we want. // Temporarily, we should compute the state only when the key event // is GDK_KEY_PRESS. // XXX If we could know the modifier keys state at the key release event, // we should cut out changingMask from modifierState. guint modifierState = aGdkKeyEvent->state; if (aGdkKeyEvent->is_modifier && aGdkKeyEvent->type == GDK_KEY_PRESS) { ModifierKey* modifierKey = keymapWrapper->GetModifierKey(aGdkKeyEvent->hardware_keycode); if (modifierKey) { // If new modifier key is pressed, add the pressed mod mask. modifierState |= modifierKey->mMask; } } InitInputEvent(aKeyEvent, modifierState); #ifdef MOZ_PLATFORM_MAEMO aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_MOBILE; #else // #ifdef MOZ_PLATFORM_MAEMO switch (aGdkKeyEvent->keyval) { case GDK_Shift_L: case GDK_Control_L: case GDK_Alt_L: case GDK_Super_L: case GDK_Hyper_L: case GDK_Meta_L: aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_LEFT; break; case GDK_Shift_R: case GDK_Control_R: case GDK_Alt_R: case GDK_Super_R: case GDK_Hyper_R: case GDK_Meta_R: aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_RIGHT; break; case GDK_KP_0: case GDK_KP_1: case GDK_KP_2: case GDK_KP_3: case GDK_KP_4: case GDK_KP_5: case GDK_KP_6: case GDK_KP_7: case GDK_KP_8: case GDK_KP_9: case GDK_KP_Space: case GDK_KP_Tab: case GDK_KP_Enter: case GDK_KP_F1: case GDK_KP_F2: case GDK_KP_F3: case GDK_KP_F4: case GDK_KP_Home: case GDK_KP_Left: case GDK_KP_Up: case GDK_KP_Right: case GDK_KP_Down: case GDK_KP_Prior: // same as GDK_KP_Page_Up case GDK_KP_Next: // same as GDK_KP_Page_Down case GDK_KP_End: case GDK_KP_Begin: case GDK_KP_Insert: case GDK_KP_Delete: case GDK_KP_Equal: case GDK_KP_Multiply: case GDK_KP_Add: case GDK_KP_Separator: case GDK_KP_Subtract: case GDK_KP_Decimal: case GDK_KP_Divide: aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_NUMPAD; break; default: aKeyEvent.location = nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD; break; } #endif // #ifdef MOZ_PLATFORM_MAEMO #else PR_LOG(gKeymapWrapperLog, PR_LOG_ALWAYS, ("KeymapWrapper(%p): InitKeyEvent, modifierState=0x%08X " "aGdkKeyEvent={ type=%s, keyval=%s(0x%X), state=0x%08X, " "hardware_keycode=0x%08X, is_modifier=%s } " "aKeyEvent={ message=%s, isShift=%s, isControl=%s, " "isAlt=%s, isMeta=%s }", keymapWrapper, modifierState, ((aGdkKeyEvent->type == GDK_KEY_PRESS) ? "GDK_KEY_PRESS" : "GDK_KEY_RELEASE"), gdk_keyval_name(aGdkKeyEvent->keyval), aGdkKeyEvent->keyval, aGdkKeyEvent->state, aGdkKeyEvent->hardware_keycode, GetBoolName(aGdkKeyEvent->is_modifier), ((aKeyEvent.message == NS_KEY_DOWN) ? "NS_KEY_DOWN" : (aKeyEvent.message == NS_KEY_PRESS) ? "NS_KEY_PRESS" : "NS_KEY_UP"), GetBoolName(aKeyEvent.IsShift()), GetBoolName(aKeyEvent.IsControl()), GetBoolName(aKeyEvent.IsAlt()), GetBoolName(aKeyEvent.IsMeta()))); if (aKeyEvent.message == NS_KEY_PRESS) { keymapWrapper->InitKeypressEvent(aKeyEvent, aGdkKeyEvent); } // The transformations above and in gdk for the keyval are not invertible // so link to the GdkEvent (which will vanish soon after return from the // event callback) to give plugins access to hardware_keycode and state. // (An XEvent would be nice but the GdkEvent is good enough.) aKeyEvent.pluginEvent = (void *)aGdkKeyEvent; aKeyEvent.time = aGdkKeyEvent->time; }
/* 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); }
/* static */ void KeymapWrapper::InitInputEvent(nsInputEvent& aInputEvent, guint aModifierState) { KeymapWrapper* keymapWrapper = GetInstance(); aInputEvent.modifiers = 0; // DOM Meta key should be TRUE only on Mac. We need to discuss this // issue later. if (keymapWrapper->AreModifiersActive(SHIFT, aModifierState)) { aInputEvent.modifiers |= MODIFIER_SHIFT; } if (keymapWrapper->AreModifiersActive(CTRL, aModifierState)) { aInputEvent.modifiers |= MODIFIER_CONTROL; } if (keymapWrapper->AreModifiersActive(ALT, aModifierState)) { aInputEvent.modifiers |= MODIFIER_ALT; } if (keymapWrapper->AreModifiersActive(SUPER, aModifierState) || keymapWrapper->AreModifiersActive(HYPER, aModifierState)) { aInputEvent.modifiers |= MODIFIER_OS; } if (keymapWrapper->AreModifiersActive(ALTGR, aModifierState)) { aInputEvent.modifiers |= MODIFIER_ALTGRAPH; } if (keymapWrapper->AreModifiersActive(CAPS_LOCK, aModifierState)) { aInputEvent.modifiers |= MODIFIER_CAPSLOCK; } if (keymapWrapper->AreModifiersActive(NUM_LOCK, aModifierState)) { aInputEvent.modifiers |= MODIFIER_NUMLOCK; } if (keymapWrapper->AreModifiersActive(SCROLL_LOCK, aModifierState)) { aInputEvent.modifiers |= MODIFIER_SCROLLLOCK; } PR_LOG(gKeymapWrapperLog, PR_LOG_DEBUG, ("KeymapWrapper(%p): InitInputEvent, aModifierState=0x%08X, " "aInputEvent.modifiers=0x%04X (Shift: %s, Control: %s, Alt: %s, " "OS: %s, AltGr: %s, CapsLock: %s, NumLock: %s, ScrollLock: %s)", keymapWrapper, aModifierState, aInputEvent.modifiers, GetBoolName(aInputEvent.modifiers & MODIFIER_SHIFT), GetBoolName(aInputEvent.modifiers & MODIFIER_CONTROL), GetBoolName(aInputEvent.modifiers & MODIFIER_ALT), GetBoolName(aInputEvent.modifiers & MODIFIER_OS), GetBoolName(aInputEvent.modifiers & MODIFIER_ALTGRAPH), GetBoolName(aInputEvent.modifiers & MODIFIER_CAPSLOCK), GetBoolName(aInputEvent.modifiers & MODIFIER_NUMLOCK), GetBoolName(aInputEvent.modifiers & MODIFIER_SCROLLLOCK))); switch(aInputEvent.eventStructType) { case NS_MOUSE_EVENT: case NS_MOUSE_SCROLL_EVENT: case NS_DRAG_EVENT: case NS_SIMPLE_GESTURE_EVENT: case NS_MOZTOUCH_EVENT: break; default: return; } nsMouseEvent_base& mouseEvent = static_cast<nsMouseEvent_base&>(aInputEvent); mouseEvent.buttons = 0; if (aModifierState & GDK_BUTTON1_MASK) { mouseEvent.buttons |= nsMouseEvent::eLeftButtonFlag; } if (aModifierState & GDK_BUTTON3_MASK) { mouseEvent.buttons |= nsMouseEvent::eRightButtonFlag; } if (aModifierState & GDK_BUTTON2_MASK) { mouseEvent.buttons |= nsMouseEvent::eMiddleButtonFlag; } PR_LOG(gKeymapWrapperLog, PR_LOG_DEBUG, ("KeymapWrapper(%p): InitInputEvent, aInputEvent has buttons, " "aInputEvent.buttons=0x%04X (Left: %s, Right: %s, Middle: %s, " "4th (BACK): %s, 5th (FORWARD): %s)", keymapWrapper, mouseEvent.buttons, GetBoolName(mouseEvent.buttons & nsMouseEvent::eLeftButtonFlag), GetBoolName(mouseEvent.buttons & nsMouseEvent::eRightButtonFlag), GetBoolName(mouseEvent.buttons & nsMouseEvent::eMiddleButtonFlag), GetBoolName(mouseEvent.buttons & nsMouseEvent::e4thButtonFlag), GetBoolName(mouseEvent.buttons & nsMouseEvent::e5thButtonFlag))); }